Home > database >  How can I write these js codes with for loop?
How can I write these js codes with for loop?

Time:06-08

I have 3 buttons and 3 content. When I click on any button, I want to show the content of that button. When I click on the other button, I want to show the content of that button and delete the content of the other button.

I managed to do this with simple logic, but how can I do it with a for loop?

photo

const content = document.querySelectorAll('.content');
const contentClose = document.querySelector('.close-content');
const btnsOpenContent = document.querySelectorAll('.show-content');


btnsOpenContent[0].addEventListener('click',
  function() {
    content[1].classList.remove('show-modal');
    content[2].classList.remove('show-modal');
    content[0].classList.add('show-modal');
  }
)

btnsOpenContent[1].addEventListener('click',
  function() {
    content[0].classList.remove('show-modal');
    content[2].classList.remove('show-modal');
    content[1].classList.add('show-modal');
  }
)

btnsOpenContent[2].addEventListener('click',
  function() {
    content[0].classList.remove('show-modal');
    content[1].classList.remove('show-modal');
    content[2].classList.add('show-modal');
  }
)

CodePudding user response:

Use simple forEach loops along with classList.toggle(className: string, force: boolean):

const content = document.querySelectorAll('.content');
const contentClose = document.querySelector('.close-content');
const btnsOpenContent = document.querySelectorAll('.show-content');

btnsOpenContent.forEach((btn, index) => {
  btn.addEventListener('click', () => {
    content.forEach((cnt, idx) => cnt.classList.toggle('show-modal', idx === index))
  })
})

CodePudding user response:

I strongly suggest to delegate, which means instead of adding a listener to each and every button, you instead capitalize on the bubbling mechanism of events, listening to clicks instead on just one common ancestor element of all buttons. Then inside the click handler you implement a guard that checks if the click actually came from a button.

Note I added hidden to the last two content to start with content 1

You can also add active to the button that was clicked and remove from the siblings

NOTE: This code does not change no matter how many buttons as long as there is a matching number of content divs.

Also note there is no need for a class to show and hide

Lastly note I implemented your close too

const nav = document.getElementById("nav");
const contents = document.getElementById("contents");
const buttons = nav.querySelectorAll("#nav .show-content");
const contentDivs = contents.querySelectorAll("div.content")
nav.addEventListener("click", e => {
  const tgt = e.target; // what was clicked?
  if (!tgt.matches(".show-content")) return; // not a button
  buttons.forEach((but,i) => contentDivs[i].hidden = but !== tgt); // hide if not the content that belongs to button
})  
contents.addEventListener("click", e => {
  const tgt = e.target;
  if (!tgt.matches(".close")) return; // not a button
  tgt.closest("div").hidden = true; // hide the div the close button is in
})  
<div id="nav">
  <button >Show 1</button>
  <button >Show 2</button>
  <button >Show 3</button>
</div>
<div id="contents">
  <div >Content 1 <button >X</button></div>
  <div  hidden>Content 2 <button >X</button></div>
  <div  hidden>Content 3 <button >X</button></div>
</div>

CodePudding user response:

The most important thing to note is that querySelectorAll does not return an array, and instead returns a NodeList. ES6 has introduced a handy method that is intended for this exact purpose NodeList.prototype.forEach().

The easiest approach in my experience to create tabbed content is to add some sort of identifier for each ".content" tab on the button triggering the event. the "data" attribute is often used for this, however, there several other options.

An example of your button html using the data attribute would look like the following:

<button  data-content="content1">Show content 1</button>
<button  data-content="content2">Show content 2</button>
<button  data-content="content3">Show content 3</button>

For this technique your content HTML would need an id that matches the identifier used on your buttons:

<div  id="content1">Some content for 1</div>
<div  id="content2">Some content for 2</div>
<div  id="content3">Some content for 3</div>

And the corresponding javascript would look similar to below:

const btnsOpenContent = document.querySelectorAll('.show-content');

btnsOpenContent.forEach((button) => {
  button.addEventListener('click', (event) => {
    let contentId = event.target.getAttribute('data-content');
    let targetContent = document.getElementById(contentId);

    // Hide all contents
    document.querySelectorAll('content').forEach((element) => {
      element.classList.remove('show-modal');
    })

    // Show selected content
    targetContent.classList.add('show-modal');
  });
});

This code can even be shortened:

const btnsOpenContent = document.querySelectorAll('.show-content');

btnsOpenContent.forEach((button) => {
  button.addEventListener('click', (event) => {
    let contentId = event.target.dataset.content;
    let targetContent = document.getElementById(contentId);

    document.querySelectorAll('content').forEach((element) => {
      element.classList.toggle('show-modal', contentId === element.id);
    })

  });
});

CodePudding user response:

Maybe something like this?

const content = document.querySelectorAll('.content');
const contentClose = document.querySelector('.close-content');
const btnsOpenContent = document.querySelectorAll('.show-content');

for (let i = 0; i <= 2; i  ) {
  btnsOpenContent[i].onclick = () => {
    for (let j = 0; j <= 2; j  ) {
      i == j ? content[j].classList.add('show-modal') : content[j].classList.remove('show-modal');
    }
  };
}
  • Related