0

I have two screens on the page. Every screen has 5 tables, there is only one table that can be seen. I want to change the visible table with these buttons. There are 2 buttons (previous, next) for each screen.

Here is my Javascript code to buttons:

document.querySelector('.screen.show .screen-table-buttons .next').onclick = function(){
    ...
}

This code works when the page is loaded the first time, but when added the show class to other screens, and I want to use it, it's not working. I want to use these buttons when the screen parent has a show class.

I changed the show class, added it to other screens, reloaded the page, and then other buttons worked on the other screen, but the first buttons didn't work.

So, I just want to use all buttons when the div parent has the show class. If the parent does not have the show class, don't work, If has it, just do it.

MrMythical
  • 8,908
  • 2
  • 17
  • 45
yusufcode
  • 391
  • 5
  • 19
  • 1
    `document.querySelector` selects only a single element that has to exist in the DOM when the method is called. A common way to attach events to non-existing elements is [event delegation](https://stackoverflow.com/questions/1687296/what-is-dom-event-delegation). – Teemu Sep 01 '21 at 09:03

2 Answers2

1

As mentioned in the comments this is a good case for event delegation - a single listener is attached to the document (or relevant ancestor) and functions are called based on target attributes.

Here it is attached to the document and it first checks if the clicked target has an ancestor with class screen.show using closest() if it does we check the classList of the target using classList.contains() to trigger the relevant function call.

function next_fn() {
  console.log('next');
}

function previous_fn() {
  console.log('previous');
}


document.addEventListener('click', (event) => {
  if (event.target.closest('.screen.show')){
    if (event.target.classList.contains('next')) {
       next_fn();
    }
    if (event.target.classList.contains('previous')) {
       previous_fn();
    }
  }
});
<div class='screen'>
  <h6>Screen no-show (buttons won't trigger)</h6>
  <button type='button' class='next'>Next</button>
  <button type='button' class='previous'>Previous</button>
</div>
<div class='screen show'>
  <h6>Screen show (only these buttons work)</h6>
  <button type='button' class='next'>Next</button>
  <button type='button' class='previous'>Previous</button>
</div>
<div class='not-screen'>
  <h6>Not-screen (buttons won't trigger)</h6>
  <button type='button' class='next'>Next</button>
  <button type='button' class='previous'>Previous</button>
</div>
pilchard
  • 12,414
  • 5
  • 11
  • 23
0

As Teemu said in the comment, the way you're binding the click event means that you're binding the click event to the button that is already visible (i.e. the one that has the show class at the moment the line you've put in the question is hit) - it isn't designed to cater for elements that may or may not exist at some point in the page lifecycle.

You'll either need to rebind the click event each time you switch the show class, or you can bind the event regardless of the show class.

In order to rebind the event each time, you'd be better off pulling the function out into its own area - something like this:

document.querySelector('.screen.show .screen-table-buttons .next').onclick = NextClicked

function NextClicked() {
    ... do the normal click event stuff, and move the show class to the other screen
    document.querySelector('.screen.show .screen-table-buttons .next').onclick = NextClicked
} 

Alternatively, you could bind the click event once and do a check to see whether the one clicked is the right one - something along these lines:

document.querySelector('.screen .screen-table-buttons .next').onclick = function(e){
    if (e.target.parentElement.parentElement.hasClass('show')){
        ...
    }
}
Andrew Corrigan
  • 1,017
  • 6
  • 23