I have a use case where i need to create a series of "cards" with tabs on top (so each card has tabs). To achieve this, I intended on having a template element which I clone and then populate. This works as expected, EXCEPT for the tabs on the cloned elements, when clicked they control the original template object instead of the current clone.
I'm assuming this is due to the event listeners that have been cloned are still connected to the original object? Is there some way to disconnect them and ensure they point and at the newly cloned objects?
Example code below...
document.querySelector("#add_card").addEventListener("click", add_card);
function add_card() {
let clone = document.querySelector('.mytab.template').cloneNode(true)
document.querySelector('#card_list').appendChild(clone);
}
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-OERcA2EqjJCMA /3y gxIOqMEjwtxJY7qPCqsdltbNJuaOe923 mo//f6V8Qbsw3" crossorigin="anonymous"></script>
<div >
<header>
<div >
<nav >
<button type="button" id="add_card">Add Card</button>
</nav>
</div>
</header>
<main>
<div id="card_list">
<div >
<div >
<div >
<ul >
<li >
<a aria-current="true" data-bs-toggle="tab" href=".one">one</a>
</li>
<li >
<a data-bs-toggle="tab" href=".two">two</a>
</li>
</ul>
</div>
<div >
<div >
<h1>ONE</h1>
</div>
<div >
<h1>Two</h1>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
CodePudding user response:
The bottom line is that tab targets must have unique identifiers. You'd have the same problem if you were to duplicate the markup itself. Here's how you might do that. Notice that I've moved the template to simplify the operation.
let iterator = 0;
document.querySelector("#add_card").addEventListener("click", add_card);
function add_card() {
let clone = document.querySelector('.template').cloneNode(true);
// add unique classes to each pane element
clone.querySelectorAll('.tab-pane').forEach((el, i) => {
el.classList.add('tab_' iterator i);
});
clone.querySelectorAll('.nav-link').forEach((el, i) => {
// update href attributes on each tab element to match panes
el.setAttribute('href', '.tab_' iterator i);
// initialize Bootstrap tabs on each tab element
const tab = new bootstrap.Tab(el)
el.addEventListener('click', event => {
event.preventDefault();
tab.show();
})
});
// append the clone
document.querySelector('#card_list').appendChild(clone);
// show the clone
clone.classList.remove('d-none');
iterator ;
}
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-OERcA2EqjJCMA /3y gxIOqMEjwtxJY7qPCqsdltbNJuaOe923 mo//f6V8Qbsw3" crossorigin="anonymous"></script>
<div >
<header>
<div >
<nav >
<button type="button" id="add_card">Add Card</button>
</nav>
</div>
</header>
<main>
<div id="card_list">
<div >
<div >
<div >
<ul >
<li >
<a aria-current="true" data-bs-toggle="tab" href=".one">one</a>
</li>
<li >
<a data-bs-toggle="tab" href=".two">two</a>
</li>
</ul>
</div>
<div >
<div >
<h1>ONE</h1>
</div>
<div >
<h1>Two</h1>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
<div >
<div >
<div >
<ul >
<li >
<a aria-current="true">one</a>
</li>
<li >
<a >two</a>
</li>
</ul>
</div>
<div >
<div >
<h1>ONE</h1>
</div>
<div >
<h1>Two</h1>
</div>
</div>
</div>
</div>