1

I'm using List.js to sort a HTML list. The JS reorders the list items in the DOM. Now I made elements in my list clickable and i need to use the (new) index of my list items.

Super Simple HTML setup:

<div id="mylist">
  <ul class="simple list">
    <li class="items">one</li>
    <li class="items">two</li>
    <li class="items">three</li>
    <li class="items">four</li>
  </ul>
</div>

JS

let nodeList = getUpdatedList();

function getUpdatedList () {
  return document.querySelectorAll('.items');
}

// here comes the List.js setup
const list = new List("mylist", { "some options" });

// and here I reassign the new List to the nodeList variable
list.on('updated', ()=>{
  nodeList = getUpdatedList();
})

// print the index on click
nodeList.forEach((item, index) => {
  item.addEventListener('click', () => {
    console.log(index);
  })
})

List.js works perfectly, the items are now reordered in the DOM after a sort method. For example

  <ul class="simple list">
    <li class="items">three</li>
    <li class="items">four</li>
    <li class="items">two</li>
    <li class="items">one</li>
  </ul>

But when I click on the first item, the console still prints 4 (the old order) although I reassigned nodelist after list.js update.

mollini
  • 35
  • 1
  • 5

1 Answers1

0

When you do this part, you're adding an event listener to each button. The value of index is locked in at that point. Each click callback is a closure that contains its own index value.

nodeList.forEach((item, index) => {
  item.addEventListener('click', () => {
    console.log(index); // this will never change
  })
})

If you want the values to change, either re-assign the click handlers or re-write the click handler function to do some other kind of logic to check the new position.

nullromo
  • 2,165
  • 2
  • 18
  • 39
  • I wrapped the whole forEach loop including the event listener inside the ListJSs `on("updated")` event, now the console prints the index twice (once the initial state, once the updated state) and after every new sort update once more, with the actual index at last position. But what I want is just the actual index. – mollini Mar 10 '23 at 22:49
  • Each time you do this, you are _adding_ a new event listener. If you want to get rid of the old listeners, you need to remove them. Otherwise there will be more and more listeners added to the items and they will all keep on firing on each click event. See [this question](https://stackoverflow.com/questions/9251837/how-to-remove-all-listeners-in-an-element) for info on how to remove the old listeners before adding new ones. You can also use [removeEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener) as long as you keep a reference to the callback. – nullromo Mar 10 '23 at 23:53
  • Of cooourse! Changed the `addEventListener()` to a `item.onclick` and it did the job! Thanks – mollini Mar 11 '23 at 07:13