Reputation: 15
I'm trying to loop through colors and change the text of an h1 to one of the colors in the loop
<h1>Color Change </h1>
<button id="btn">Click Here</button>
const btn = document.querySelector('#btn')
btn.addEventListener('click', () => {
const h1 = document.querySelector('h1')
const colors = ['red', 'yellow', 'brown', 'green', 'blue']
for (let i = 0; i < colors.length; i++) {
h1.style.color = colors[i]
}
})
It's only returning the last color, while I want to loop through all of the colors. I'm not sure why
Upvotes: 0
Views: 2098
Reputation: 10055
What you need is a generator (or alternatively a closure as suggested by Andy) which provides you with the next colour which will then be set within the click event:
const h1 = document.querySelector("h1");
const btn = document.querySelector("#btn");
function* ColorLoop(color_palette) {
let currentIndex = -1
while (true) {
// looping infinitely around an array based on:
// https://benfrain.com/looping-infinitely-around-an-array-in-javascript
let nextIndex = ++currentIndex % color_palette.length;
yield color_palette[nextIndex];
}
}
const colors = ColorLoop(["red", "yellow", "brown", "green", "blue"]);
btn.addEventListener("click", () => {
h1.style.color = colors.next().value;
});
<h1>Color Change </h1>
<button id="btn">Click Here</button>
Note: By changing the generator's (and parameter's) name, you have even a reusable generator looping around any array.
Upvotes: 0
Reputation: 9855
Try to outline the algorithm in plain human language first:
Now you can convert this to the code:
// there is a title element, a button element, and a predefined set of colors
const h1 = document.querySelector('h1')
const btn = document.querySelector('#btn')
const colors = ['red', 'yellow', 'brown', 'green', 'blue'];
// no color is chosen initially
let currentColorIndex = -1;
// whenever the button is clicked ...
btn.addEventListener('click', () => {
// grab the next color from the set (if the current color is the last one, grab the first one then)
const nextColorIndex = ++currentColorIndex % colors.length;
// apply the next color to the title element
h1.style.color = colors[nextColorIndex];
});
<h1>Color Change </h1>
<button id="btn">Click Here</button>
Upvotes: 3
Reputation: 63524
You don't want to loop over all the colours when you click the button. You should keep a count of the current colour index, update the text colour, and then increase the count.
My usual technique for this kind of problem is to use a closure so we limit the number of global variables we use.
const btn = document.querySelector('#btn')
const h1 = document.querySelector('h1');
btn.addEventListener('click', handleClick(), false);
const colors = ['red', 'yellow', 'brown', 'green', 'blue'];
// Closures work by returning a function from
// the function that is called which maintains
// a copy of its local lexical envionment (in
// this case `count`). The function that is returned
// is the function assigned to the button click listener
// So, we initialise the count to zero
function handleClick(count = 0) {
// Return a function that maintains a copy
// of `count`
return function () {
// If the count is less than the length
// of the colors array change the text colour
// and then increase the count
if (count < colors.length) {
h1.style.color = colors[count];
++count;
}
}
}
<h1>Color Change </h1>
<button id="btn">Click Here</button>
Upvotes: 1
Reputation: 8495
I think the logic you're after is to loop through the colors at each click:
const btn = document.querySelector('#btn')
const h1 = document.querySelector('h1')
const colors = ['red', 'yellow', 'brown', 'green', 'blue']
let i = 0;
btn.addEventListener('click', () => {
h1.style.color = colors[i]; // to change the color
h1.innerHTML = colors[i]; // to change the text
i = (i + 1) % colors.length;
})
<h1>Color Change </h1>
<button id="btn">Click Here</button>
Upvotes: 0