Search code examples
javascriptdomwebpolymercomponents

querySelectorAll not returning all elements in DOM


I am working on a side project in which the HTML file is generated and sent to the front end, where it is being formatted and displayed using Polymer 3 and other technologies.

Long story short, when I call querySelectorAll, it does not return, for example, all anchor tags in the document:

document.querySelectorAll("a");

Rather, it only seems to acknowledge the existence of tags if they are direct children of the node upon which querySelectorAll is called. So, if I have:

<div>
  <custom-tag1>
    <custom-tag2>
      <a href="http://www.google.com">Google</a>
      <a href="http://www.yahoo.com">Yahoo!</a>
      <a href="http://www.amazon.com">Amazon</a>
    </custom-tag2>
  </custom-tag2>
</div>

I've found I have to first get the document object, then the body object, then anything living on the top level of the body object (let's say the above div is immediately inside body, for example), etc.

So if I (finally!) get a reference to the body, I can call:

theBody.querySelectorAll("a");

and it will return an empty list. I have to do something like this:

theBody.querySelectorAll("div")[0].querySelectorAll("custom-tag1")[0].querySelectorAll("custom-tag2")[0].querySelectorAll("a");

in order to get a list of the anchor elements!

But, if anchors exist anywhere else, it won't get them.

Notes: Polymer 3 server is running. The situation may be complicated by the fact that some of the elements (at least those I see in Chrome's debugger) are shadow roots.

Thus, sometimes, we end up doing this:

someNode.shadowRoot.querySelectorAll("a");  

or similar.


Solution

  • If you do a console.log in all your custom-tagX elements' ready methods (and in onload in <body>), then you will see why. The result you would see would look something like this ...

     body is ready
     custom-tag1 is ready
     custom-tag2 is ready
    

    ... meaning that when the body is done loading, then your Polymer specific custom elements will load.

    So to solve this, you need to send out an event when a specific element has loaded, and let body listen for it with addEventListener.

    However, this is not how you should think when it comes to Polymer.

    Why do you want the <a> tags in the first place?

    I would instead build a behavior, and add it to custom-tag2, and every time you want to do whatever you want with the <a> tags in a custom element, just add that behavior to the element. (I looked it up, and it's just for Polymer 1)

    I would instead use mixins to share code that does something to the <a> tags.

    https://www.polymer-project.org/3.0/docs/devguide/custom-elements#mixins