Klyner
Klyner

Reputation: 4163

Appending more than two child elements to an element gives a strange behaviour

I have a very strange behaviour and I don't know what causes it.

I loop through all of the id's which javascript can find within my html page. Every time when the 'id' startsWith a specific label, it goes into my if statement.

Within this if-statement I am creating several elements such as P,H1 and HR. Within my 'html'-page I've got 3 unique id's which are DIV's and should go into the if statement. This worked well(picture left [ 1]), until...

I tried to append more than two child elements to those DIV elements. The first two DIV elements are extended as expected. The last one has not been extended though. At the moment that there are more than two elements added to the parent, the 3th DIV (standardArticle3) does not pass the if statement. (picture right [2])

Hopefully the code and scenario picture can make this story clearer:

home.component.ts

var allElements = document.getElementsByTagName("*");
console.log(allElements);
for (var i = 0, n = allElements.length; i < n; ++i) {
  var el = allElements[i];
  var foundElementId = el.id;
  console.log(foundElementId);
  if (foundElementId.startsWith("standardArticle"))
  {
    var standardArticleElement = this.jsonReaderService.getStandardArticleContent(foundElementId.substring(15, foundElementId.length));

    var titleElement = document.createElement("h1");
    var titleText = document.createTextNode(standardArticleElement.title);
    titleElement.appendChild(titleText);

    var contentElement = document.createElement("p");
    contentElement.innerHTML = standardArticleElement.content;

    var thematicBreak = document.createElement("hr");
    thematicBreak.style.borderTopColor = "black";

    var thematicBreakTwo = document.createElement("hr");
    thematicBreakTwo.style.borderTopColor = "black";

    // Child elements are all being appended the right way, but the last DIV will never be extended
    el.appendChild(titleElement);
    el.appendChild(thematicBreak);
    el.appendChild(contentElement);
    el.appendChild(thematicBreakTwo);
  }
}

home.component.html

    // other content
    <div id="standardArticle1" class="col-sm-6">
    </div>
    // other content
    <div id="standardArticle2" class="col-sm-6 pull-right">
    </div>
    // other content
    <div id="standardArticle3" class="col-sm-6">
    </div>

enter image description here Scenario's 1 and 2.

Does anybody have an idea why this is happening?

Upvotes: 1

Views: 75

Answers (2)

Saleh Hindi
Saleh Hindi

Reputation: 301

I think I know what your problem is. Let's see what happens when you loop over all the elements on the page: for (var i = 0, n = allElements.length; i < n; ++i)

If there are 10 elements on the page, then n is set to 10. But then as you reach your if statement and add elements, n is still equal to 10 but you now have additional elements on the page. It looks like Mikael Lennholm said those more concisely and provided a good solution.

Upvotes: 1

Lennholm
Lennholm

Reputation: 7470

document.getElementsByTagName() returns a live HTMLCollection, and your collection includes every element on the page. This means that when you append new elements, these elements get included in the collection but since you iterate up to the original length of the collection, you'll miss the last elements of the collection (the same number of elements as the number of elements you added).

It seems like a better solution to your problem would be to add a class to all elements you want to find and just get those ones with document.getElementsByClassName():

var allElements = document.getElementsByClassName("standard-article");

... and then you add your class name to your HTML:

// other content
<div id="standardArticle1" class="standard-article col-sm-6">
</div>
// other content
<div id="standardArticle2" class="standard-article col-sm-6 pull-right">
</div>
// other content
<div id="standardArticle3" class="standard-article col-sm-6">
</div>

With this approach you don't need your id.startsWith("standardArticle") if statement either.

Upvotes: 2

Related Questions