I am using the following code to create instances of a Web component:
<main></main>
<template id="my-template">
<style>
p { color: green; }
</style>
<p>I'm in Shadow DOM.</p>
</template>
<script>
let tmpl = document.querySelector('#my-template');
class AppDrawer extends HTMLElement {
constructor() {
super();
this.root = this.attachShadow({mode: 'open'});
//this.root.appendChild(tmpl.content.cloneNode(true));
}
set details(user) {
this.root.innerHTML = `<h2> ${user.company.name}</h2>`
}
}
window.customElements.define('app-drawer', AppDrawer);
async function asyncCall() {
const res = await fetch("https://jsonplaceholder.typicode.com/users");
const json = await res.json();
const main = document.querySelector("main");
json.forEach(user=> {
const el = document.createElement("app-drawer");
el.details = user;
main.appendChild(el);
});
}
asyncCall();
</script>
By running the above, I am getting some names as output. So far so good. Now, trying to use the <template> instead by deleting the comment inside the constructor and deleting el.details = user; as well, I am getting multiple I'm in Shadow DOM.
My question is how can I achieve the dynamic content (different user names) of the first case by using the second approach?
You just need to replace your el.details = user with a statement that adds the appropriate HTML to the shadow DOM. (This makes the setter irrelevant, so I have commented it out.)
user.company.name into the web component as an attribute during its construction, rather than setting the value imperatively afterward.
(Note that I removed the <p> element from the template in favor of simply including the <h2> element where the userCompanyName will be displayed.)
let tmpl = document.querySelector('#my-template');
class AppDrawer extends HTMLElement {
constructor() {
super();
this.root = this.attachShadow({ mode: 'open' });
// Creates a copy of the `<template>` element's contents
const copy = tmpl.content.cloneNode(true);
// Selects a target element withinin the copy
const header = copy.querySelector("H2");
// Copies the component instance's `usernamecomp` attribute to its `userCompName` property
this.userCompName = this.getAttribute("usercompname");
// Sets the target element's contents equal to the`userCompName` property
header.innerHTML = this.userCompName;
// Appends the augmented copy to the shadowDOM
this.root.appendChild(copy);
}
}
window.customElements.define('app-drawer', AppDrawer);
async function asyncCall() {
const res = await fetch("https://jsonplaceholder.typicode.com/users");
const json = await res.json();
const main = document.querySelector("main");
json.forEach(user => {
// Identifies the string to pass into the component instance as an attribute
const userCompName = user.company.name;
// Writes HTML to be used to instantiate an `<app-drawer>` element with a `usercompname` attribute
const drawerInstance = `<app-drawer usercompname=${userCompName}></app-drawer>`;
// Creates the new `<app-drawer>` element, appended to the `<main>` element
main.insertAdjacentHTML("beforeend", drawerInstance);
});
}
asyncCall();
<main></main>
<template id="my-template">
<style>
h2 { color: green; }
</style>
<h2>I'm in Shadow DOM.</h2>
</template>
You can pass the loaded value as a parameter to the custom element create with new:
json.forEach( user => main.appendChild( new AppDrawer( user ) ) )
You just need to define the custom element constructor() with an argument:
constructor( user ) {
...
}
See a complete example below:
class AppDrawer extends HTMLElement {
constructor( user ) {
super()
this.attachShadow( {mode: 'open'} )
.innerHTML = `<style> p { color: green } </style>
<p> ${user.company.name} </p>`
}
}
window.customElements.define( 'app-drawer', AppDrawer )
async function asyncCall() {
const res = await fetch( "https://jsonplaceholder.typicode.com/users" )
const json = await res.json()
const main = document.querySelector( "main" )
json.forEach( user => main.appendChild( new AppDrawer( user ) ) )
}
asyncCall()
<main></main>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With