user171780
user171780

Reputation: 3085

Why is getElementsByTagName not returning the elements with the tag name?

I am facing this strange problem that I have brought down to a MWE. I am not an expert in this, sorry if it is something obvious.

I have this HTML document:

var floats = document.getElementsByTagName("custom-float");
for (var i = 0; i < floats.length; i++) {
  var caption = floats[i].getElementsByTagName("float-caption");
  if (caption.length == 0) {
    throw 'This float has no caption!';
  }
}
<p>
  A paragraph.
  <custom-float>
    <div style="display: flex;">
      <image src="1.svg"></image>
    </div>
    <float-caption>A description of the image.</float-caption>
  </custom-float>
</p>

For some reason when I open the HTML (both in Firefox 90.0 and Brave 1.26.77 in Linux) the This float has no caption! error is thrown, so this means that getElementsByTagName is not returning the float-caption element.

For my surprise, I noticed that if I remove the <div style="display: flex;"></div> wrapper and/or if I place the </p> before <custom-float>, everything works as expected. I.e. the following two HTML documents work fine:

var floats = document.getElementsByTagName("custom-float");
for (var i = 0; i < floats.length; i++) {
  var caption = floats[i].getElementsByTagName("float-caption");
  if (caption.length == 0) {
    throw 'This float has no caption!';
  }
}
<p>
  A paragraph.
  <custom-float>
    <image src="1.svg"></image>
    <float-caption>A description of the image.</float-caption>
  </custom-float>
</p>

var floats = document.getElementsByTagName("custom-float");
for (var i = 0; i < floats.length; i++) {
  var caption = floats[i].getElementsByTagName("float-caption");
  if (caption.length == 0) {
    throw 'This float has no caption!';
  }
}
<p>
  A paragraph.
</p>
<custom-float>
  <div style="display: flex;">
    <image src="1.svg"></image>
  </div>
  <float-caption>A description of the image.</float-caption>
</custom-float>

Upvotes: 3

Views: 2525

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1074266

Your elements are being relocated in the DOM, because the given HTML is invalid: div elements can't be inside p elements, which can only have phrasing content, not flow content like a div. If you inspect the structure with the DOM inspector in your browser, you'll see that the div and its contents have been moved out of the p (and thus out of the custom-float) into the p's parent.

If you replace the p with a div (or remove the div, as you discovered), you don't have that problem, because the HTML is no longer invalid.

Here's replacing the p with a div:

var floats = document.getElementsByTagName("custom-float");
for(var i = 0; i < floats.length; i++) {
    var caption = floats[i].getElementsByTagName("float-caption");
    if (caption.length == 0) {
        throw 'This float has no caption!';
    }
}
<!DOCTYPE html>
<html>
 <head>
    <title>MWE</title>
    <meta charset="utf-8">
 </head>
 
 <body>
    <div>
        A paragraph.
        <custom-float>
            <div style="display: flex;">
                <image src="1.svg"></image>
            </div>
            <float-caption>A description of the image.</float-caption>
        </custom-float>
    </div>
 </body>
</html>

Upvotes: 4

It's easier to use querySelectorAll with just the tag

var floats = document.querySelectorAll("custom-float");
for(var i = 0; i < floats.length; i++) {
    var caption = floats[i].querySelectorAll("float-caption");
    if (caption.length == 0) {
        throw 'This float has no caption!';
    }
}

Upvotes: -3

Related Questions