Initialisation of Custom Elements Inside Document Fragment

Tags: , , , ,



Consider this HTML template with two flat x-elements and one nested.

<template id="fooTemplate">
  <x-element>Enter your text node here.</x-element>
  <x-element>
    <x-element>Hello, World?</x-element>
  </x-element>
</template>

How to initialise (fire constructor) all custom elements in cloned from fooTemplate document fragment without appending it to DOM, neither by extending built-in elements with is="x-element"; either entire fragment.

class XElement extends HTMLElement {
  constructor() { super(); }
  foo() { console.log( this ); }
} customElements.define( 'x-element', XElement );

const uselessf = function( temp ) {
  const frag = window[ temp ].content.cloneNode( true );

  /* Your magic code goes here:
  */ do_black_magic( frag );

  for (const e of  frag.querySelectorAll('x-element') )
    e.foo(); // This should work.

  return frag;
};

window['someNode'].appendChild( uselessf('fooTemplate') );

Note that script executes with defer attribute.

Answer

We can initialise template with this arrow function:

const initTemplate = temp =>
  document.createRange().createContextualFragment( temp.innerHTML );

const frag = initTemplate( window['someTemplate'] );

Or with this method defined on template prototype (I prefer this way):

Object.defineProperty(HTMLTemplateElement.prototype, 'initialise', {
  enumerable: false,
  value() {
    return document.createRange().createContextualFragment( this.innerHTML );
  }
});

const frag = window['someTemplate'].initialise();

In any case in result this code will work fine:

for (const elem of  frag.querySelectorAll('x-element') )
  elem.foo();

window['someNode'].appendChild( frag );

I’m not sure if these methods are the most effective way to initialise custom elements in template.

Also note that there is no need for cloning template.



Source: stackoverflow