3

I am looking into structuring vanilla web-components. I have previously used Polymer and like the fact that you can have the template, styles and JavaScript in one file for your component. I want to achieve this with 'vanilla' web components if possible but can't work out how. I've taken the code from here and added it to a file which I am using as follows:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    
    <title>Component test</title>
    
    <link rel="import" href="x-foo-from-template.html">
  </head>
  <body>
    <x-foo-from-template></x-foo-from-template>
  </body>
</html>

This fails because when we try to select the template it does not exist because at that point the template is not in the DOM (right?).

Is there any way to achieve this? I personally prefer this approach to creating the HTML in the JavaScript using document.createElement.

Rubén
  • 34,714
  • 9
  • 70
  • 166
Ben Thomas
  • 3,180
  • 2
  • 20
  • 38

2 Answers2

5

There are 2 main methods to get the template from the imported document:

1. From the import property of the <link> element

The <link rel=import> elements own an import property that contains the imported document. You can perform a querySelector call on it to fetch the <template>:

var doc = document.querySelector( 'link[href$="x-foo-from-template.html"]').import
var template = doc.querySelector( 'template' )

Then import the template in the custom element (or in its Shadow DOM) using either importNode() or cloneNode().


2. From the ownerDocument property of currentScript

When a script is parsed, the global value document.currentScript references the script being parsed, and therefore its propery ownerDocument is a reference to the document that owns the script. You can perform a querySelector call on it:

var template = document.currentScript.ownerDocument.querySelector( 'template' )

Note: the currentScript value is set temporarily, so it won't work any more in subsequent calls, like connectedCallback() or attachedCallback(), so you'll have to memorize it in a persistent variable at parse time, to reuse it later when needed.

Supersharp
  • 29,002
  • 9
  • 92
  • 134
  • Thanks for this answer. Shame I can't do it exactly how I want but this will do! – Ben Thomas Sep 21 '16 at 08:31
  • What do you want exactly? Maybe I could improve my answer. – Supersharp Sep 21 '16 at 09:16
  • A note, if you're using ` – Clint Priest Oct 13 '18 at 17:47
  • Sorry for commenting on an old answer, but why wouldn't `document.querySelector( 'template' )` be the same as `document.currentScript.ownerDocument.querySelector( 'template' )`? – aderchox Sep 21 '22 at 06:26
0

For latecomers:

As of 2021, HTML imports feature has been deprecated (MDN Link).

I would not recommend it, you can instead: create a template tag with a data- attribute to html imports. Write a script that runs on all those elements with that attribute and access those html parts using fetch() in the script, add that fetched import to the template tag and use it eg: template.content.cloneNode( true ).

Giuseppe Canale
  • 470
  • 7
  • 15