0

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>

1 Answer 1

1

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>

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you very much. I don't think I wold have got here this way on my own. I don't totally understand the first line of the setColour function. get the element data for counter and .... colours.indexOf etc?? I also don't understand where the html text is getting updated. I see where the current colour class is being removed but is the span just being overwritten instead of being emptied first?
Correct about the .html() function. that just overwrites the inner HTML of that element. you don't have to "clear" it out before. api.jquery.com/html. For the .indexOf() function, that just tells which position the passed in item is in the array. for example ['a', 'b', 'c'].indexOf('b') would return 1 since it's the 2nd item in the array (and since it starts at 0) So we are using it as a way to look up the index of the color that we already have a name for. We then "store" it as data on the HTML element itself, instead of in a JS variable.
Check out api.jquery.com/data for more info, but basically $('#my-element').data('foo', 'bar') will save data with a "lookup key" of "foo" and a value of "bar". If I want to read that data back out later I can do $('#my-element').data('foo') which will return "bar" to me
Also, check out my updated answer that uses a loop instead of needing to type out a<div class="square"><span></span></div> element 100 times

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.