Search code examples
javascripthtmlcssvariablescolors

How to make a counter variable start from 0 for every single object when function is called?


I am making a simple website with a bunch of divs in a container. When you click on a div it changes a color. When div is pressed 8 times it goes back to a starting color which is "LightSlateGray". The problem is if someone clicks on another div after clicking on the first one the variable that I used to count the clicks doesn't start from 0.

For example:
First div is clicked and its color changed to red. When the other div is clicked its background color changes to green but I want it to turn red and as user keeps pressing the second div it should turn green the blue then orange etc.

var order = 0;
function changeColour(item)
{
    
    order++;
    if(order == 1)
    {
        item.style.backgroundColor = 'red';
    }
    else if(order == 2)
    {
        item.style.backgroundColor = 'Green';
    }
    else if(order== 3)
    {
        item.style.backgroundColor = 'Blue';
    }
    else if(order == 4)
    {
        item.style.backgroundColor = 'Orange';
    }
    else if(order == 5)
    {
        item.style.backgroundColor = 'Yellow';
    }
    else if(order == 6)
    {
        item.style.backgroundColor = 'Purple';
    }
    else if(order == 7)
    {
        item.style.backgroundColor = 'Black';
    }
    if(order == 8)
    {
        item.style.backgroundColor = 'LightSlateGray'
        order = 0
    }
        
}

I tried to put var order = 0 in the function itself but that was just dumb because it made other part of code useless

Is there any way of accomplishing that without creating a ton of variables?


Solution

  • As other answers show: You may want to use an array for the colours as you essentially refer to them by an index (i.e. order).

    You want each element to have its own index. You can use custom data attributes (data-*) on each element to let them keep track of their own index:

    const colors = ["red","green","blue","orange","yellow","purple","black","lightslategray"];
    
    document.querySelectorAll("#wrapper>div").forEach(div => {
      div.dataset.order = 0;
      div.addEventListener("click", () => changeColor(div));
    });
    
    function changeColor(element) {
      let order = Number(element.dataset.order);
      
      element.style.backgroundColor = colors[order];
      
      element.dataset.order = (order + 1) % colors.length;
    }
    #wrapper {border: 1px solid black;width: fit-content}
    #wrapper>div {
      width: 100px;
      height: 100px;
    }
    <div id="wrapper">
      <div></div>
      <div></div>
    </div>

    We can also defer the custom attribute's initialization to when we want to change an element's colour. If we then use event delegation for the click events, we can add more <DIV>s without any setup:

    const colors = ["red","green","blue","orange","yellow","purple","black","lightslategray"];
    
    const wrapper = document.getElementById("wrapper");
    wrapper.addEventListener("click", (evt) => {
      // `evt.target` is the clicked target
      const isChildOfWrapper = evt.target !== wrapper && wrapper.contains(evt.target);
      if (isChildOfWrapper) {
        changeColor(evt.target);
      }
    });
    
    document.querySelector("button").addEventListener("click", () => {
      // No setup required (apart from appending the new element)
      wrapper.append(document.createElement("div"));
    });
    
    function changeColor(element) {
      let order = Number(element.dataset.order ?? 0); // Use 0 as fallback
      
      element.style.backgroundColor = colors[order];
      
      element.dataset.order = (order + 1) % colors.length;
    }
    #wrapper {
      border: 1px solid black;
      display: flex;
      flex-wrap: wrap;
      width: fit-content;
      max-width: 100%;
    }
    #wrapper>div {
      width: 100px;
      height: 100px;
    }
    <div id="wrapper">
      <div></div>
      <div></div>
    </div>
    <button>Add <code>&lt;DIV&gt;</code></button>


    You can also modify InSync's solution to use event delegation, as in that solution the elements also keep track of their indices (but encoded as background colours).