2

This problem has me absolutely stumped. I'm trying to include HTML snippets with Javascript and it works, but for some reason it decides to also include duplicate snippets in various other locations.

Here is a screenshot of what I mean: WTFFFFFFFF

It also varies the number and location of these random includes.

This is the function I use to include. It searches through the document and finds div elements with the attribute include="x.html"

function include() {
  var allElements;
  var fileName;
  var includeRequest;

  allElements = document.getElementsByTagName("*");
  for (var i = 0; i < allElements.length; i++) {

    if (allElements[i].getAttribute("include")) {

      fileName = allElements[i].getAttribute("include");
      includeRequest = new XMLHttpRequest();
      includeRequest.open("GET", fileName, true);

      includeRequest.onreadystatechange = function() {
        if (includeRequest.readyState == 4 && includeRequest.status == 200) {

          allElements[i].removeAttribute("include");

          allElements[i].innerHTML = includeRequest.responseText;
          include();
          delete includeRequest;
          includeRequest = null;
        }
      }     
      includeRequest.send();

      return;   
    }
  }
}

This is the function that gets tags from an html file containing articles, and adds them to the list of tags in the box on the right. As you can see, in one place the footer is added to the list instead of the tag. I don't know why.

function getTags() {
    var taglist = document.getElementById("taglist");

    var tagsRequest = new XMLHttpRequest();

    tagsRequest.open("GET", "blogstubs.html", true);
    tagsRequest.responseType = "document";

    tagsRequest.onreadystatechange = function() {
        if (tagsRequest.readyState == 4 && tagsRequest.status == 200) {

            var tagsResponse = tagsRequest.responseXML;
            var tags = tagsResponse.getElementsByClassName("tag");
            var tags = getUnique(tags);



            var len = tags.length;


            for (var i = 0; i < len; i++) {
                var li = document.createElement("li"); 

                li.appendChild(tags[i]);

                taglist.appendChild(li);

            }
            delete tagsRequest;
            tagsRequest = null;
        }
    }      

  tagsRequest.send();

}

Javascript only solution please. Ideas?

  • `delete` in javascript does not work how you seem to think it works. – Ryan Nov 03 '16 at 21:00
  • @Ryan I left nothing untried. Though this probably has a simple solution. – GodProbablyExists Nov 03 '16 at 21:04
  • 2
    See http://stackoverflow.com/questions/1451009/javascript-infamous-loop-issue regarding your `for(i)` loop in the `include()` function. – Barmar Nov 03 '16 at 21:05
  • My guess would be that it has something to do with sync and async code. Maybe `allElements[i]` inside of the `onreadystatechange` function is not what it should be and that's why it appends the html to the wrong elements. Instead of using global scope in this function try passing `allElements[i]` as a parameter. – Dmitry Gamolin Nov 03 '16 at 21:22

1 Answers1

1

I copied your website (I hope you don't mind) and tested it with my changes, it seems to be working now without this bug. Here's what I did:

1) I created a new function, don't forget to change the name to whatever you prefer:

function newFunction(allElements, includeRequest) {
    allElements.removeAttribute("include");
    allElements.innerHTML = includeRequest.responseText;
    include();
    delete includeRequest;
    includeRequest = null;
}

2) I changed the include() function to look like this:

function include() {
    var allElements;
    var fileName;
    var includeRequest;

    allElements = document.getElementsByTagName("*");
    for (var i = 0; i < allElements.length; i++) {

        if (allElements[i].getAttribute("include")) {
            var element = allElements[i];

            fileName = element.getAttribute("include");
            includeRequest = new XMLHttpRequest();
            includeRequest.open("GET", fileName, true);

            includeRequest.onreadystatechange = function() {
                if (includeRequest.readyState == 4 && includeRequest.status == 200) {
                    return newFunction(element, includeRequest);
                }
            }     
            includeRequest.send();

            return; 
        }
    }
}

I think the problem was caused by async nature of AJAX requests, like I said in the comment. So you need to pass the variables to your AJAX call instead of using the global scope, that's why you need this new callback function.

In other words, in the original code the AJAX variable allElements[i] wasn't in sync with your loop's allElements[i], so while in your loop it would be 5, in AJAX function (which executed separately and not in order with the loop) it would be 3, 6 or whatever else. That is why it would append the html to the element that seems random. Think of AJAX as of someone who doesn't care about the order of your loops, someone who really doesn't like to wait while someone else is counting and does everything in his own order.

Dmitry Gamolin
  • 934
  • 1
  • 12
  • 29