Search code examples
htmlweb-componentcustom-element

Nested web component's `attachedCallback` not running on appended


I'm playing with W3C web components.

I have a homepage, which includes component A:

<!-- homepage.html -->
<link rel='import' href='a.html'>
<component-a></component-a>

In component A I include another component B:

<!-- a.html -->
<link rel='import' href='b.html'>
<template>
  <component-b></component-b>
  <component-b></component-b>
</template>
<script>
  void function() {
    var currentDocument = document.currentScript.ownerDocument
    function getTemplate(selector) {
      return currentDocument.querySelector(selector).content.cloneNode(true)
    }

    var proto = Object.create(HTMLElement.prototype)
    proto.attachedCallback = function() {
      console.log('a')
      this.appendChild(getTemplate('template'))
    }
    document.registerElement('component-a', { prototype: proto })
  }()
</script>

B's code is very similar to A:

<!-- b.html -->
<template>
  <span>b</span>
</template>
<script>
  void function() {
    var currentDocument = document.currentScript.ownerDocument
    function getTemplate(selector) {
      return currentDocument.querySelector(selector).content.cloneNode(true)
    }

    var proto = Object.create(HTMLElement.prototype)
    proto.attachedCallback = function() {
      console.log('b')
      this.appendChild(getTemplate('template'))
    }
    document.registerElement('component-b', { prototype: proto })
  }()
</script>

What's weird is, when the page is loaded, I could only see "a" in console. I was expecting "b" for twice as well. And the component B isn't really parsed.

What even weird is that, if I run following code in console:

document.querySelector('component-a').innerHTML += ''

it suddenly gives me twice "b".

Here's a screenshot:

enter image description here


Solution

  • A friend gives me a solution, use document.importNode instead of cloneNode:

    function getTemplate(selector) {
      // return currentDocument.querySelector(selector).content.cloneNode(true)
      return document.importNode(currentDocument.querySelector(selector).content, true)
    }
    

    And it works perfectly.