Reputation: 45
I may have set this up wrong, but I have a button that's set up in JS to change the color of all elements through a class they all share. They dont have onClick or anything just a class. I am trying to use an if/else statement to cycle through different color themes. Considering this is my first time using JS on my project (and ever) its proving to be quite a challenge. I have the script tag at the bottom of the body element and triple checked my button ID name. If it just cant work in the way I am hoping would love to know sooner rather than later lmao. The other variables for border and back are colors I intend on changing as well.
const themeColor = document.getElementById("theme-click-home");
const allColor = document.querySelectorAll(".theme-change");
const allBorder = document.querySelectorAll(".theme-border");
const allback = document.querySelectorAll(".theme-back");
themeColor.addEventListener("click", (e) => {
let count = 0;
count++;
if (count === 6) {
count = 0;
} else if (count === 1) {
allColor.style.setProperty("color", "red", "!important");
} else if (count === 2) {
allColor.style.setProperty("color", "red", "!important");
} else if (count === 3) {
allColor.style.setProperty("color", "red", "!important");
} else if (count === 4) {
allColor.style.setProperty("color", "red", "!important");
} else if (count === 5) {
allColor.style.setProperty("color", "red", "!important");
}
});
---edit---
const themeColor = document.getElementById("theme-click-home");
const allColor = document.querySelectorAll(".theme-change");
const allBorder = document.querySelectorAll(".theme-border");
const allback = document.querySelectorAll(".theme-back");
themeColor.addEventListener("click", (e) => {
let count = 0;
count++;
if (count === 6) {
count = 0;
} else if (count === 1) {
for (i = 0; i < themeColor.length; i++) {
allColor[i].style.setProperty("color", "red", "!important");
}
} else if (count === 1) {
for (i = 0; i < themeColor.length; i++) {
allColor[i].style.setProperty("color", "blue", "!important");
}
} else if (count === 1) {
for (i = 0; i < themeColor.length; i++) {
allColor[i].style.setProperty("color", "green", "!important");
}
} else if (count === 1) {
for (i = 0; i < themeColor.length; i++) {
allColor[i].style.setProperty("color", "purple", "!important");
}
} else if (count === 1) {
for (i = 0; i < themeColor.length; i++) {
allColor[i].style.setProperty("color", "yellow", "!important");
}
}
});
Upvotes: 0
Views: 1846
Reputation: 45
Solved it. Below is the code if anyone is interested. testFunction()
is attached to an onclick
let allColor = document.querySelectorAll(".theme-change");
const allBorder = document.querySelectorAll(".theme-border");
const allBack = document.querySelectorAll(".theme-back");
const noShadow = document.querySelectorAll("*");
let count = -1;
colorArray = [
"white",
"blue",
"red",
"green",
"purple",
"maroon",
"yellow",
"pink",
"teal",
"crimson",
];
function testFunction() {
if (count >= colorArray.length - 1) {
count = -1;
}
count++;
allColor.forEach((item) => {
item.style.color = colorArray[count];
});
allBorder.forEach((item) => {
item.style.border = `solid ${colorArray[count]}`;
});
allBack.forEach((item) => {
item.style.backgroundColor = colorArray[count];
});
noShadow.forEach((item) => {
item.style.textShadow = "none";
item.style.boxShadow = "none";
});
}
Upvotes: 0
Reputation: 122906
It's not necessary to use setProperty
for changing inline style properties. For handling you may want to consider event delegation. To store the clicks count, you can use a data-attribute.
Here's a (minimal reproducable) example for you with the aforementioned in mind.
document.addEventListener(`click`, handle);
function handle(evt) {
// only react when the event originated from button#bttn
if (evt.target.id === `bttn`) {
// [somestring].split is a bit of a trick to create
// an array from a (delimited, here by |) string.
// The array has 7 entries. Arrays are 'zero based',
// meaning that colors[0] is 'initial', colors[2] is 'blue',
// in other words: the third color from the array is colors[2]
const colors = `initial|red|blue|green|purple|rgb(211,211,21)|#c0c0c0`
.split(`|`);
// get the value of [data-clicked], convert to number (+) and add 1 to it
const clicks = +evt.target.dataset.clicked + 1;
// if n of clicks equals the array length, reset [data-clicked] to zero
// otherwise the value of [clicks].
// Note: using [colors.length] to determine when to reset,
// you can vary the number of colors used (added #c0c0c0, so [data-clicked]
// resets after the sixth click)
evt.target.dataset.clicked = clicks === colors.length ? 0 : clicks;
// set the color of div#allColor to colors[value of [data-clicked]]
document.querySelector(`#allColor`).style.color =
colors[evt.target.dataset.clicked];
}
}
body {
margin: 2rem;
font: normal 12px/15px verdana, arial;
}
#allColor {
margin-top: 1em;
}
[data-clicked]:after {
content: ' 'attr(data-clicked) ' click(s)';
}
<button id="bttn" data-clicked="0"></button>
<div id="allColor">
<h3>div#AllColor</h3>
<div>Chapter one</div>
<div>Chapter two</div>
<div>...</div>
</div>
Or maybe you meant this?
document.addEventListener(`click`, handle);
function handle(evt) {
if (evt.target.id === `bttn`) {
const themes = document.querySelectorAll(`[data-theme-color]`);
const clicks = +evt.target.dataset.clicked;
evt.target.dataset.clicked = clicks + 1;
themes[clicks].style.color = themes[clicks].dataset.themeColor;
if (clicks === themes.length-1) {
bttn.textContent += ` => all done`;
return evt.target.setAttribute(`disabled`, true);
}
}
if (evt.target.id === `redo`) {
const btn = document.querySelector(`#bttn`);
btn.dataset.clicked = 0;
btn.removeAttribute(`disabled`);
btn.textContent = ``;
document.querySelectorAll(`[data-theme-color]`)
.forEach(el => el.style.color = `initial`);
}
}
body {
margin: 2rem;
font: normal 12px/15px verdana, arial;
}
#allColor {
margin-top: 1em;
}
[data-clicked]:before {
content: ' 'attr(data-clicked) ' click(s)';
}
<button id="bttn" data-clicked="0"></button>
<button id="redo">Again</button>
<div id="allColor">
<h3>div#AllColor</h3>
<div data-theme-color="orange">Chapter one</div>
<div data-theme-color="red">Chapter two</div>
<div data-theme-color="blue">Chapter three</div>
<div data-theme-color="green">Chapter four</div>
<div data-theme-color="purple">Chapter five</div>
<div data-theme-color="rgb(211,211,21)">Chapter six</div>
<div data-theme-color="#c0c0c0">Chapter seven</div>
</div>
Upvotes: 0
Reputation: 63524
querySelectorAll
will return an nodelist. You can't attach a listener to the result. You have to iterate over the nodelist. You should be using CSS classes rather than setting the style of the elements directly. You're also setting the same style for each count in your condition which seems redundant. You can iterate over the nodelist and apply the same class to each element.
You can store colours in an array, and then use the index of the forEach
callback to access them and apply the style.
// Cache the button, and the theme-change elements
const themeColor = document.getElementById('theme-click-home');
const allColor = document.querySelectorAll('.theme-change');
const colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'];
// Add the listener to the button
themeColor.addEventListener('click', handleClick, false);
function handleClick() {
// For each element in `allColor` add the class found
// from the corresponding index of the colors array
allColor.forEach((el, i) => el.classList.add(colors[i]));
}
.red { color: red; }
.orange { color: orange; }
.yellow { color: yellow; }
.green { color: green; }
.blue { color: blue; }
.indigo { color: indigo; }
.violet { color: violet; }
<button id="theme-click-home">Change theme</button>
<div class="theme-change">Theme 1</div>
<div class="not-theme-change">Theme 2</div>
<div class="theme-change">Theme 3</div>
<div class="theme-change">Theme 4</div>
<div class="theme-change">Theme 5</div>
<div class="theme-change">Theme 6</div>
<div class="theme-change">Theme 7</div>
<div class="theme-change">Theme 8</div>
Having written that I think I understand what your issue is. You want to cycle through the elements and apply a new style to each element in sequence.
// Cache the button, and the theme-change elements
const themeColor = document.getElementById('theme-click-home');
const allColor = document.querySelectorAll('.theme-change');
const colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'];
// Call handleClick. It returns a new function
// that acts as the listener
themeColor.addEventListener('click', handleClick(), false);
// Set the count to zero
function handleClick(count = 0) {
// Return the function that acts as the listener
return function () {
// If count is less that the nodelist length
// add a style to the new element in the nodelist,
// and then increment the count
if (count < allColor.length) {
allColor[count].classList.add(colors[count]);
++count;
}
}
}
.red { color: red; }
.orange { color: orange; }
.yellow { color: yellow; }
.green { color: green; }
.blue { color: blue; }
.indigo { color: indigo; }
.violet { color: violet; }
<button id="theme-click-home">Change theme</button>
<div class="theme-change">Theme 1</div>
<div class="not-theme-change">Theme 2</div>
<div class="theme-change">Theme 3</div>
<div class="theme-change">Theme 4</div>
<div class="theme-change">Theme 5</div>
<div class="theme-change">Theme 6</div>
<div class="theme-change">Theme 7</div>
<div class="theme-change">Theme 8</div>
Upvotes: 1
Reputation: 690
You can create a function to change elements style and call it with what you want to change: You can find all properties you can set here https://www.w3schools.com/jsref/dom_obj_style.asp
const themeColor = document.getElementById("theme-click-home");
const allColor = document.querySelectorAll(".theme-change");
const allBorder = document.querySelectorAll(".theme-border");
const allback = document.querySelectorAll(".theme-back");
let count = 0;
themeColor.addEventListener("click", (e) => {
count++;
if (count >= 6) count = 0;
if (count === 1) changeStyle(allColor, 'color', "red"); // changes text color
else if (count === 2) changeStyle(allColor, 'color', "blue");
else if (count === 3) changeStyle(allBorder, 'border', "thick solid #0000FF"); // changes border
else if (count === 4) changeStyle(allColor, 'color', "green");
else if (count === 5) changeStyle(allback, 'backgroundColor', 'red'); // changes background
});
function changeStyle(elements, property, value) {
for (var i = 0; i < elements.length; i++) {
elements[i].style[property] = value;
}
}
.theme-change {
width: 100px;
margin: 5px;
}
<span id="theme-click-home">Click to Change</span>
<div class="theme-change theme-border">a</div>
<div class="theme-change theme-back">b</div>
<div class="theme-change theme-back">c</div>
<div class="theme-change theme-border">d</div>
Upvotes: 0
Reputation: 1939
I don't understand the logic for increasing the count variable, but anyways you should move it outside the function closure.
You could do something like this:
const themeColor = document.getElementById('theme-click-home')
const allColor = document.querySelectorAll('.theme-change')
const allBorder = document.querySelectorAll('.theme-border')
const allback = document.querySelectorAll('.theme-back')
let count = 0
themeColor.addEventListener('click', e => {
count++
const color = count % 2 === 0 ? 'red' : 'green'
allColor.forEach(elem => {
elem.style.color = color
})
})
Upvotes: 0