Search code examples
javascriptweb-component

How to access elements of imported html from script inside imported html


I want to make a custom element which will self-register on html import.

custom-element.html:

<html>
  <...>
  <body>
    <template id="myTemplate">
    </template>
  </body>
  <script src="my-script.js">
</html>

my-script.js:

let customElementPrototype = Object.create(HTMLElement.prototype);
customElementPrototype.createdCallback = function () {
  // somewhere here i want to access <template> to insert it in element
  // I've tried document.querySelector("#myTemplate") and
  // document.currentScript.ownerDocument.querySelector.querySelector("#myTemplate")
  // they don't work either, result of querySelector is null
}
document.registerElement("custom-element", customElementPrototype);

Usage:

<html>
<head>
  <link rel="import" href="custom-element.html">
</head>
<...>

Solution

  • Inside the createdCallback the context is the custom-element and not the ownerDocument. You can see this by console.log(this); inside the createdCallback which logs (from my plunker example):

    <div is="custom-element">
    </div>
    

    In my-script.js you can capture a reference to the ownerDocument and use it inside your callback. This will allow your custom-element to access both it's own DOM and the DOM of the imported HTML. e.g.

    var mainDoc = document.currentScript.ownerDocument;
    

    The full my-script.js (script.js in my plunker):

    var mainDoc = document.currentScript.ownerDocument;
    
    var CustomElementPrototype = Object.create(HTMLElement.prototype);
    CustomElementPrototype.createdCallback = function () {
      console.log(this); //the div 
      //import the contents of the template
      var clone = document.importNode(mainDoc.querySelector('#myTemplate').content, true);
      //append template to div
      this.appendChild(clone);
    };
    
    document.registerElement("custom-element", {
        prototype: CustomElementPrototype,
        extends: 'div'
    });
    

    combined with a template that has some default value (this document will be available via mainDoc):

    <html>
      <body>
        <script src="script.js"></script>
        <template id="myTemplate">
          hello world
          <br>
          from template
        </template>
      </body>
    </html>
    

    And the HTML to pull it all in and use it:

    <!DOCTYPE html>
    <html>
    
      <head>
        <link rel="stylesheet" href="style.css">
        <link rel="import" href="custom-element.html">
      </head>
    
      <body>
        <h1>Hello Plunker!</h1>
        <div is="custom-element"></div>
      </body>
    
    </html>
    

    https://plnkr.co/edit/jO3ci8vLxolHhvtGxJQ5

    This was a helpful reference: http://webcomponents.org/articles/introduction-to-html-imports/