codebloo
codebloo

Reputation: 85

How can I use jQuery to cycle through an array on click for multiple items?

I have an array of colors. On load I cycle through the array and add it as a class and text to each div with the class "square"

On click I want to toggle the class/text on that square to the next item in the array.

I have hit 2 snags that I think are related and I know it needs a bit of clean up.

  1. On load the array is starting with the second item in the array instead of the first unless I set the counter to =-1 instead of =0

  2. When I click any square it skips over the next item in the array. and then proceeds normally.

I tried different methods for .each but keep getting trapped in different incorrect results and returning to the last thing that almost works.

When I click a square I expect it to update to the next colour in the array in relation to it's current colour. I also expect the grid to start with black in the top left corner.

$(document).ready(function(){

//array of colours
 var colours = ['black', 'blue', 'cyan', 'green', 'magenta', 'red', 'yellow'],
counter = 0;
function nextColour(){
   counter = (counter + 1) % colours.length;
}
  
// on Load iterate over all the squares in the grid
// add the colour class in order of the array & matching text to span
  $('.square').each(function(){
    nextColour();
    $(this).addClass(colours[counter]);
    $(this).find("span").html(colours[counter]);
  });
  
 // on click change the square to the next colour in the array
$('.square').click(function(){
     $(this).removeClass(colours);
     $(this).find("span").html("");
      nextColour();
  // Add next colour in array for this item
     $(this).addClass(colours[counter]);
     $(this).find("span").html(colours[counter]);
  });
  
});
    
.squares{
  background-color:#dedede;
  display: grid;
  grid-template-columns: repeat(10, 1fr);
  grid-auto-rows: 50px;
  height:500px;
  width:500px;}
.square{
  align-items:center;
  color:#000;
  display:flex;
  justify-content:center;
  outline: 1px solid #000;}
.square span{
  display:none;
  font-size:11px;
  text-align:center;
text-transform:capitalize;}
.square:hover span{display:block;}

.black{
  background-color:#000;
  color:#fff;}
.blue{
  background-color:#00f;
  color:#fff;}
.cyan{background-color:#0ff;}
.green{background-color:#0f0;}
.magenta{background-color:#F0F;}
.red{background-color:#f00;}
.yellow{background-color:#ff0;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section class="squares">
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  
   <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  
    <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  
   <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div> 
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div> 
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  
   <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div> 
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  
   <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>

</section>

Upvotes: 0

Views: 54

Answers (1)

Chris Barr
Chris Barr

Reputation: 33992

You only have the counter variable declared once, for all the squares. So if you start it at 0 and make 4 squares, now counter is at 4. I think you might want to have a different counter for each square, and then just start each counter at a different value. When you update the counter you aren't always getting the "next" color since you are sharing the same concept of what "next" means between all the squares.

I've re-worked it a bit to separate the way the initial colors (that's how I spell it!) are generated, vs. how the "next" color is chosen. basically we generate an index, and save it as data on each element, so each one can maintain it's own counter.

I've also added user-select: none to your CSS so that the color names are not accidentally highlighted when the squares are clicked.

I hope this works for you! Let me know if something isn't clear about what I've changed.

$(document).ready(function() {

  //array of colours
  var colours = ['black', 'blue', 'cyan', 'green', 'magenta', 'red', 'yellow']

  function getNextColour($element) {
    var counter = $element.data('counter');
    counter = (counter + 1) % colours.length;
    return colours[counter];
  }

  function setColour($element, colourName) {
    $element.data('counter', colours.indexOf(colourName));
    $element.addClass(colourName);
    $element.find("span").html(colourName);
  }

  // on Load iterate over all the squares in the grid
  // add the colour class in order of the array & matching text to span
  $('.square').each(function(i) {
    var colourIndex = i % colours.length;
    setColour($(this), colours[colourIndex]);
  });

  // on click change the square to the next colour in the array
  $('.square').click(function() {
    $(this).removeClass(colours);
    var nextColor = getNextColour($(this));
    setColour($(this), nextColor);
  });

});
.squares {
  background-color: #dedede;
  display: grid;
  grid-template-columns: repeat(10, 1fr);
  grid-auto-rows: 50px;
  height: 500px;
  width: 500px;
}

.square {
  align-items: center;
  color: #000;
  display: flex;
  justify-content: center;
  outline: 1px solid #000;
}

.square span {
  display: none;
  font-size: 11px;
  text-align: center;
  text-transform: capitalize;
  user-select: none;
  /* <----- prevent text selection when clicking! */
}

.square:hover span {
  display: block;
}

.black {
  background-color: #000;
  color: #fff;
}

.blue {
  background-color: #00f;
  color: #fff;
}

.cyan {
  background-color: #0ff;
}

.green {
  background-color: #0f0;
}

.magenta {
  background-color: #F0F;
}

.red {
  background-color: #f00;
}

.yellow {
  background-color: #ff0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section class="squares">
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>

  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>

  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>

  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>

  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>

  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>
  <div class="square"><span></span></div>

</section>


Edit

here is an more simplified/optimized version of what is above. mostly this removes the 100 identical html elements, we can use a JS loop to create these instead of needing to type them all out.

$(document).ready(function() {

  //array of colours
  var colours = ['black', 'blue', 'cyan', 'green', 'magenta', 'red', 'yellow']

  function getNextColour($element) {
    //get the data from the passed in element
    var counter = $element.data('counter');
    //update the counter and then return the new color name
    counter = (counter + 1) % colours.length;
    return colours[counter];
  }

  function setColour($element, colourName) {
    //With the passed in element...
    $element
      .addClass(colourName)  //Add a class
      .data('counter', colours.indexOf(colourName)) //update the data with the new color index number
      .find('span').text(colourName); //change the text of the color name
  }
  
  //Select the container once
  var $container = $('#squares-container');
  
  //Create 100 squares in a loop
  for (var i = 0; i < 100; i++) {
    //Using the index from the loop, go through the array of colors
    var colourIndex = i % colours.length;
    //Create a new element
    var $newSquare = $('<div class="square"><span></span></div>');
    //Set the color on it
    setColour($newSquare, colours[colourIndex]);
    //Put it inside of the container
    $container.append($newSquare);
    
    $newSquare.click(function() {
      $(this).removeClass(colours);
      var nextColor = getNextColour($(this));
      setColour($(this), nextColor);
    });
  }

});
#squares-container {
  background-color: #dedede;
  display: grid;
  grid-template-columns: repeat(10, 1fr);
  grid-auto-rows: 50px;
  height: 500px;
  width: 500px;
}

.square {
  align-items: center;
  color: #000;
  display: flex;
  justify-content: center;
  outline: 1px solid #000;
}

.square span {
  display: none;
  font-size: 11px;
  text-align: center;
  text-transform: capitalize;
  user-select: none; /* <----- prevent text selection when clicking! */
}

.square:hover span {
  display: block;
}

.black {
  background-color: #000;
  color: #fff;
}

.blue {
  background-color: #00f;
  color: #fff;
}

.cyan {
  background-color: #0ff;
}

.green {
  background-color: #0f0;
}

.magenta {
  background-color: #F0F;
}

.red {
  background-color: #f00;
}

.yellow {
  background-color: #ff0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section id="squares-container"></section>

Upvotes: 1

Related Questions