Home > Software engineering >  How to run same function on multiple elements?
How to run same function on multiple elements?

Time:02-11

I created a web page with 3 counters that can be triggered separately, but I have a problem with the count function I can't use it on the 3 counters.

I manage to retrieve the index of each button but I don't know how to use it to trigger each counter separately.

can you help me to solve this problem please ?

Here is my code.

"use strict";


/* ___________________________Déclarer les variables et les fonctions______________________________ */

/* Déclaration des variables */
var item = document.querySelectorAll('.slider-item');
var str = document.querySelectorAll('.buttons--start');
var stp = document.querySelectorAll('.button--stop');
var start = 0;
var end = 0;
var diff = 0;
var timer = 0;

/* Fonction chrono */
function chrono(){
    end = new Date();
    diff = end - start;
    diff = new Date(diff);
    var sec = diff.getSeconds();
    item.innerHTML = sec;
    timer = setTimeout("chrono()", 10);
}

/* Fonction pour déclancher le chrono */
function chronoStart(i){
    start = new Date();
    chrono();
    console.log('start ' i);
}

/* Fonction pour arrêter et rénitialiser le chrono */
function chronoStop(i){
    clearTimeout(timer)
    item[i].innerHTML = "0";
    start = new Date();
    console.log('stop ' i);
}

/* Fonction qui change la couleur du background */
function changeColor(i){
    let bgColor = '#'   Math.random().toString(16).substr(-6);
    item[i].style.backgroundColor = bgColor;
}

/* ___________________________Écouter les événements__________________________________ */

/* Appeler la fonction qui déclanche le chrono lorsqu'on clique sur start*/
for (let i=0; i<item.length; i  )
{
    str[i].addEventListener('click',(e)=>{
        chronoStart(i);
    }); 
    //currentPos = i ;
}

/* Appeler la fonction qui arrête le chrono lorsqu'on clique sur stop*/
for (let i=0; i<item.length; i  )
{
    stp[i].addEventListener('click',(e)=>{
        chronoStop(i);
    }); 
}

/* Appeler la fonction qui change la couleur du background lorsque l'évenement est déclancher*/

for (let i=0; i<item.length; i  )
{
    item[i].addEventListener("click",(e)=>{
        changeColor(i);
    });
}
body {
    font-family: Arial, sans-serif;
}

.wrapper {
    /* display: flex;
    flex-flow: column wrap;
    position: fixed;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    padding: 50px; */
}

.slider {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-grow: 1;
}

.slider-item {
    font-size: 120px;
    font-weight: bold;
    padding: 15px;
    background-color: yellow;
    user-select: none;
}

.buttons {
    margin-top: 15px;
    text-align: center;
}

.buttons button {
    display: inline-block;
    padding: 15px;
    font-size: 16px;
    color: #fff;
    border: none;
    outline: none;
    background-color: #000;
    cursor: pointer;
}
  <div >
            <div >
                <div >0</div>
            </div>
            <div >
                <button  type="button">Start</button>
                <button  type="button">Stop</button>
            </div>
            
        </div>
        <div >
            <div >
                <div >0</div>
            </div>
            <div >
                <button  type="button">Start</button>
                <button  type="button">Stop</button>
            </div>
            
        </div>
        <div >
            <div >
                <div >0</div>
            </div>
            <div >
                <button  type="button">Start</button>
                <button  type="button">Stop</button>
            </div>
            
        </div>

CodePudding user response:

The issue is because you have multiple instances of the same repeated HTML content yet within your logic you do not keep the relevant references to the correct elements when an event occurs.

A simpler way to achieve this would be to loop through the containing elements and find the relevant child elements to bind event handlers to, or to update the content of.

The simple version of this logic would be something like this:

"use strict";

document.querySelectorAll('.chrono-wrapper').forEach(el => {
  const container = el;
  const item = el.querySelector('.slider-item');
  const str = el.querySelector('.buttons--start');
  const stp = el.querySelector('.button--stop');

  var start = 0;
  var end = 0;
  var diff = 0;
  var timer = 0;

  function chrono() {
    end = new Date();
    diff = end - start;
    diff = new Date(diff);
    var sec = diff.getSeconds();
    item.innerHTML = sec;
    timer = setTimeout(chrono, 10);
  }

  function chronoStart() {
    start = new Date();
    chrono();
  }

  function chronoStop() {
    clearTimeout(timer)
    item.innerHTML = "0";
    start = new Date();
  }

  function changeColor(i) {
    let bgColor = '#'   Math.random().toString(16).substr(-6);
    item.style.backgroundColor = bgColor;
  }

  str.addEventListener('click', chronoStart);  
  stp.addEventListener('click', chronoStop);
});
body {
  font-family: Arial, sans-serif;
}

.chrono-wrapper {
  /* display: flex;
    flex-flow: column wrap;
    position: fixed;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    padding: 50px; */
}

.slider {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-grow: 1;
}

.slider-item {
  font-size: 120px;
  font-weight: bold;
  padding: 15px;
  background-color: yellow;
  user-select: none;
}

.buttons {
  margin-top: 15px;
  text-align: center;
}

.buttons button {
  display: inline-block;
  padding: 15px;
  font-size: 16px;
  color: #fff;
  border: none;
  outline: none;
  background-color: #000;
  cursor: pointer;
}
<div >
  <div >
    <div >0</div>
  </div>
  <div >
    <button  type="button">Start</button>
    <button  type="button">Stop</button>
  </div>
</div>
<div >
  <div >
    <div >0</div>
  </div>
  <div >
    <button  type="button">Start</button>
    <button  type="button">Stop</button>
  </div>
</div>
<div >
  <div >
    <div >0</div>
  </div>
  <div >
    <button  type="button">Start</button>
    <button  type="button">Stop</button>
  </div>
</div>

CodePudding user response:

As Rory pointed out while I was doodling this up, you have repeated markup but a single set of variables tracking the timers.

You could remedy this by iterating over the occurrences in the HTML and setting up distinct handlers for each. Here's one way you could do that:

"use strict";

function init() {
  // get elements whose id begins with "slider-"
  const sliders = document.querySelectorAll('[id^=slider-]');

  // set up event listeners for each occurrence:
  sliders.forEach(s => {
    // the setInterval/timeout identifier for this instance
    let timerId;
    
    // get references to the child elements we need
    const startButton = s.querySelector('.buttons--start');
    const stopButton = s.querySelector('.button--stop');
    const display = s.querySelector('.slider-item');
    
    // add a start button click listener
    startButton.addEventListener('click', () => {
      // clear existing timer if already running
      clearTimeout(timerId);
      
      // capture the start time
      const start = new Date();
      
      // function to update the display
      const update = () => {
        display.innerHTML = ((Date.now() - start) / 1000).toFixed(1);
      }
      
      // start a timer, update the timerId variable
      timerId = setInterval(update, 100)
      
      // add a listener for the stop button to kill this timer
      const stopHandler = () => clearInterval(timerId);
      stopButton.addEventListener('click', () => {
        stopHandler();
        // only needs to run once; remove the listener
        stopButton.removeEventListener('click', stopHandler);
      });
    });
  });
}

// kick it off
init();
body {
  font-family: Arial, sans-serif;
}

.wrapper {
  /* display: flex;
    flex-flow: column wrap;
    position: fixed;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    padding: 50px; */
}

.slider {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-grow: 1;
}

.slider-item {
  font-size: 120px;
  font-weight: bold;
  padding: 15px;
  background-color: yellow;
  user-select: none;
}

.buttons {
  margin-top: 15px;
  text-align: center;
}

.buttons button {
  display: inline-block;
  padding: 15px;
  font-size: 16px;
  color: #fff;
  border: none;
  outline: none;
  background-color: #000;
  cursor: pointer;
}
<div  id="slider-1">
  <div >
    <div >0</div>
  </div>
  <div >
    <button  type="button">Start</button>
    <button  type="button">Stop</button>
  </div>

</div>
<div  id="slider-2">
  <div >
    <div >0</div>
  </div>
  <div >
    <button  type="button">Start</button>
    <button  type="button">Stop</button>
  </div>

</div>
<div  id="slider-3">
  <div >
    <div >0</div>
  </div>
  <div >
    <button  type="button">Start</button>
    <button  type="button">Stop</button>
  </div>

</div>

  • Related