Home > Software engineering >  Bootstrap nav tabs control original when cloned
Bootstrap nav tabs control original when cloned

Time:10-13

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>

  • Related