I'm new to vanilla javascript as i have experience only in reactjs. I'm trying to display a web component i have created in two places. But it displays only once. What can be the issue here?
My web component
class MyComponent extends HTMLElement {
constructor() {
// always call super() first
super();
console.log('constructed!');
}
connectedCallback() {
// console.log(this.getAttribute("filter"));
this.innerHTML = `
<html>
<div id="templates" class="template_style">
<template id="book-template">
<li><span class="title"></span> — <span class="author"></span></li>
</template>
<ul id="books"></ul>
</div>
</html>
`;
}
}
customElements.define('my-component', MyComponent);
JS code used to populate the web component with data
import JsonObj from './debts.js';
const books = JsonObj;
function appendBooks() {
const booksList = document.getElementById('books');
const fragment = document.getElementById('book-template');
// Clear out the content from the ul
booksList.innerHTML = '';
console.log(books);
// Loop over the books and modify the given template
books.debts.forEach(book => {
// Create an instance of the template content
const instance = document.importNode(fragment.content, true);
// Add relevant content to the template
instance.querySelector('.title').innerHTML = book.bank;
instance.querySelector('.author').innerHTML = book.category;
// Append the instance ot the DOM
booksList.appendChild(instance);
});
}
document.getElementById('templates').addEventListener('change', (event) => appendBooks());
appendBooks('book-template');
HTML code where i'm using the above component
<div>
<div class="sub_container">
<label>Users in Debt</label>
<input placeholder="Search by user name" class="input_style">
<my-component filter="userdebt"></my-component>
</div>
<div class="sub_container">
<label>Debts</label>
<input placeholder="Search by debt description" class="input_style">
<my-component filter="debt"></my-component>
</div>
</div>
So as seen in the html code i have used </my-component>
in two places but i can only see the first instance only. I have used a console.log inside constructor in my component and i can see it calls 2 times. But in the view i can see only the first instance. How can i fix this?
You should add id
to the web-component itself so that you can query using the id
of the parent for the child nodes that is contained within it
In your code the when queried using the id
of the child of the web-component it fetched you the first one since you had duplicated ids, in my code I gave each <my-component>
tag a unique id
so that I can only query for its child:
class MyComponent extends HTMLElement {
constructor() {
// always call super() first
super();
console.log('constructed!');
}
connectedCallback() {
// console.log(this.getAttribute("filter"));
this.innerHTML = `
<div id="templates" class="template_style">
<template id="book-template">
<li><span class="title"></span> — <span class="author"></span></li>
</template>
<ul id="books"></ul>
</div>
`;
}
}
customElements.define('my-component', MyComponent);
const books = [{bank : "foo", category: "bar"}];
function appendBooks(id) {
const comp = document.getElementById(id);
//query for the child of the parent web-component
const booksList = comp.querySelector('#books');
const fragment = comp.querySelector('#book-template');
// Clear out the content from the ul
booksList.innerHTML = '';
// Loop over the books and modify the given template
books.forEach(book => {
// Create an instance of the template content
const instance = document.importNode(fragment.content, true);
// Add relevant content to the template
instance.querySelector('.title').innerHTML = book.bank;
instance.querySelector('.author').innerHTML = book.category;
// Append the instance ot the DOM
booksList.appendChild(instance);
});
}
function addChangeListener(id){
document.getElementById(id)
.querySelector('#templates')
.addEventListener('change', (event) => appendBooks());
}
appendBooks('comp1'); //for componenent having id = comp1
appendBooks('comp2'); //for componenent having id = comp2
addChangeListener('comp1')
addChangeListener('comp2')
<div>
<div class="sub_container">
<label>Users in Debt</label>
<input placeholder="Search by user name" class="input_style">
<my-component id="comp1" filter="userdebt"></my-component>
</div>
<div class="sub_container">
<label>Debts</label>
<input placeholder="Search by debt description" class="input_style">
<my-component id="comp2" filter="debt"></my-component>
</div>
</div>