0

I have various questions about the webfundamentals implementations, i have read that a true web component must have shadowDOM for css encapsulation, customElements for the logic of the component which i really love, and HTML Temapltes and import, so im trying to do it all in a customElement component and i have encounter with many and many issues that i find really hard to debug, i will enlist them all.

  1. Does i have to insert html template into the document to actually get it? cant i get its content from js only? and in case i have to, when i intent to replace a shadowHost content hows is it works, i mean i got the template (the link) inside the shadowRoot, my actuall problem is that when i do querySelector(link[rel="import"]).import.querySelector("template") its null after the .import function tag and when i insert that function into the document, it actually gets the template content, heres the doc.

enter image description here

Watching that screenshot i got 2 more questions

  1. Should i use shadowHost.innerHTML = file.querySelector(link[rel="import"]).import.querySelector("template") to use the tag and copy its content inside the shadowRoot element? i mean how can i implement that approach? im using Angular as first example, they use an HTML file (which im guessing its a template or slots tag) and then they add it into the component as parameters on the constructor, so how with HTMLTemplates and HTMLImport i can implement that behaviour, i have used the documented functions but it doesnt works in the final phase.

  2. Should i keep <link rel="import"> inside the shadowRoot or inside the document.head? can i implement the template without the need of adding it into the document?

I have been trying for days to do a simple customElement with shadowDOM that works completly fine, the problem is when i try to add an external to make it more robust.

Any helps? suggestions? i can show some functions that i use on the components to have an idea.

class EgHeader extends HTMLElement {
  constructor() {
    super();
    this.shadowHost = shadowHost.bind(this);
    this.shadowStyle = shadowStyle.bind(this);
    this.shadowTemplate = shadowTemplate.bind(this);

    this.host = this.shadowHost();
  }

  connectedCallback() {
    this.defaultProperties();

    let importSelector = this.host.querySelector(`link[rel="import"]`);
    console.log(importSelector);
    // this.host.appendChild(importSelector.cloneNode(true));
    this.host.innerHTML = importSelector.import.querySelector(
      "template"
    ).content;
  }

  defaultProperties() {
    this.getAttributeNames().forEach(key => {
      console.log(key);
      if (key === "css") {
        return this.shadowStyle(this.getAttribute(key));
      }

      if (key === "template") {
        return this.shadowTemplate(this.getAttribute(key));
      }
    });
  }
}

customElements.define("eg-header", EgHeader);

function shadowHost() {
  let root = this.attachShadow({
    mode: "open"
  });

  return root;
}

function shadowStyle(stylesheet) {
  let link = document.createElement("link");
  link.rel = "stylesheet";
  link.href = stylesheet + ".css";

  this.host.appendChild(link.cloneNode(true));
  return link;
}

function shadowTemplate(link) {
  var template = document.createElement("link");
  template.rel = "import";
  template.id = `${link}-template`;
  template.href = link + ".html";

  document.head.appendChild(template);
  this.host.appendChild(template);
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <title>Page Title</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <script src="./Header.js"></script>
  <script src="./index.js"></script>
</head>

<body>
  <eg-header css="./Header" template="./Header">
  </eg-header>
</body>

</html>



// Separated file called Header.html
<template>
  <nav>This is X element</nav>
<script>
  console.warn("Executed when the template is activated.");
</script>
</template>

1 Answers1

0

i have read that a true web component must have shadowDOM for css encapsulation, customElements for the logic of the component which i really love, and HTML Temapltes and import

What you've read is quite outdated:

  1. HTML Imports are deprecated so you should use another method to load templates.
  2. Because of #1, HTML templates (aka <template> elements) are often replaced par template literals.

Templates literals can be define in Javascript. This way they can be defined in a classical Javascript file or in the ES6 module.

By the way, if you still want to use HTML Imports (not recommanded) , you'll need to use a polyfill.

<link rel="import"> should be put in the <head> element of the main document, not in the Shadow DOM.

If you want to use <template> you don't need to append it to the main document.

var template = document.createElement( 'template' )
template.innerHTML = `
    <h1>Title</h1>
    <div>Content</div>
`
...
this.shadowRoot.appendChild( template.content.clone( true ) )
Supersharp
  • 29,002
  • 9
  • 92
  • 134
  • how can i use the tempalte without adding it into the document? i want it to be separated from the style and the logic (js) @Supersharp – Eduardo Gonzalez Feb 28 '19 at 20:00
  • @EduardoGonzalez see this post for a separated JS file for template https://stackoverflow.com/q/53063500/4600982 – Supersharp Feb 28 '19 at 20:28