2

Hello :) I'm coding dark mode switch and I came across a problem I can't figure out.

I loop through an array which contains items looking like that: { className: 'h3dark', elementId: 'h2'}. Then I use forEach loop to apply each class to ALL elements with a defined ID. Unfortunately it's applying each class on only first html element with an ID. Do you know how it can be fixed?

HTML

<h1 id="h1" class="h1">COLOR</h1>   <!--Color changed-->
<h1 id="h2" class="h1">COLOR</h1>   <!--Color changed-->
<h1 id="h3" class="h1">COLOR</h1>   <!--Color changed-->
<h1 id="h1" class="h1">COLOR</h1>   <!--Color not changed-->
<h1 id="h2" class="h1">COLOR</h1>   <!--Color not changed-->
<h1 id="h3" class="h1">COLOR</h1>   <!--Color not changed-->
    
<button onclick="darkSwitch()">CHANGE COLOR</button>

</div>

JAVASCRIPT

// checking if cookie exists
var cookieState = Cookies.get('darkMode');

// First visit - cookieState is undefined
// If cookie exists we are parsing it to get a boolean
if(cookieState === undefined) {
  var isDarkmodeEnabled = false;
} else {
  var isDarkmodeEnabled = JSON.parse(cookieState)
};

// Cookie doesn't exist: darkMode = false 
// Cookie exists: darkMode = true/false
var darkMode = isDarkmodeEnabled;

// Add dark mode classes and elements' ids
// className - a name of a class with dark mode attributes 
// elementId - an id of an element a class will be added to
var darkClasses = [
  { className: 'h1dark', elementId: 'h1'},
  { className: 'h2dark', elementId: 'h3'},
  { className: 'h3dark', elementId: 'h2'},           
];


// Adding classes on page load if darkmode is enabled
window.onload = addClassesOnLoad();

// Changing darkMode state and adding or removing classes
function darkSwitch() {

  // Setting darkMode to its opposite value
  darkMode = !darkMode;

  if(darkMode === true) {
    // Looping through an array and deleting classes
    darkClasses.forEach(item => {
        document.getElementById(item.elementId).classList.add(item.className)
    });
  } else {
  // Looping through an array and deleting classes
    darkClasses.forEach(item => {
      document.getElementById(item.elementId).classList.remove(item.className)
    });  
  };
  // Saving darkMode state to the cookie
  Cookies.set('darkMode', darkMode);
}

// Adding classes on page load if darkmode is enabled
function addClassesOnLoad() {

  if(darkMode === true){
            
    darkClasses.forEach(item =>{ 
                document.getElementById(item.elementId).classList.add(item.className)
    });
  };
}

That's how it looks like and how it should

3
  • 3
    DON'T REUSE IDs! It's bad practice. Use classes or attributes if you need something reusable. Note how the method is called document.getElementById. Not getElementsById. It's only supposed to return one element. Commented Sep 18, 2021 at 23:18
  • Do you think it could have something to do with the IDs being the same...in the half that isn't working? That would be my first clue if I was troubleshooting. Commented Sep 18, 2021 at 23:19
  • id attribute is unique on page, So it is not correct HTML to have two divs with same id! Commented Sep 18, 2021 at 23:19

2 Answers 2

1

Try like following snippet:

/*const cookieState = Cookies.get('darkMode');
if(cookieState === undefined){
    let isDarkmodeEnabled = false;
}else{
    let isDarkmodeEnabled = JSON.parse(cookieState)
};
let darkMode = isDarkmodeEnabled;*/
let darkMode = true //replace with isDarkmodeEnabled

const darkClasses = [
    { className: 'h1dark', classId: 'h1'},
    { className: 'h2dark', classId: 'h2'},
    { className: 'h3dark', classId: 'h3'},           
];

toggleDarkMode()

function darkSwitch(){
  darkMode = !darkMode;
  toggleDarkMode()
  //Cookies.set('darkMode', darkMode);
}

function toggleDarkMode(){
  darkClasses.forEach(item => { 
    const h1s = document.querySelectorAll(`.${item.classId}`)
    h1s.forEach(h => h.classList.toggle(item.className))
  })
}
.h1dark {
  color: orange;
}
.h2dark {
  color: red;
}
.h3dark {
  color: violet;
}
<h1 id="1" class="h1">COLOR</h1>   
<h1 id="2" class="h2">COLOR</h1>  
<h1 id="3" class="h3">COLOR</h1>  
<h1 id="4" class="h1">COLOR</h1>  
<h1 id="5" class="h2">COLOR</h1>   
<h1 id="6" class="h3">COLOR</h1>   

<button onclick="darkSwitch()">CHANGE COLOR</button>

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

7 Comments

Thanks for your answer! It didn't work out but I made small changes and it works now. Maybe I implemented your code in wrong way.
I don't know why, I'm coding for few days and can't really analyze code, but i posted solution below :)
Nice mate, I'm glad that you find solution. If you need any help, I'm ready to help, if I can ofc. cheers :)
item.defaultClass is element from your array darkClasses , and . is sign for css class (for example .h1). So when you got element from array, let's say item.defaultClass=h1 we add . so we can refer to css class .h1
You can learn more here
|
1

Thanks to Nikola Pavicevic's answer I figured it out.

darkClasses.forEach(item => {
    document.getElementById(item.elementId).classList.add(item.className)
});

Changed to:

darkClasses.forEach(item => {
    var element = document.querySelectorAll(`.${item.defaultClass}`)
    element.forEach(h => h.classList.add(item.newDarkClass))
});

and

var darkClasses = [
        { newDarkClass: 'h1dark', defaultClass: 'h1'},
        { newDarkClass: 'h2dark', defaultClass: 'h2'},
        { newDarkClass: 'h3dark', defaultClass: 'h3'},           
    ];


    <h1 class="h1">COLOR</h1>   <!--Color changed-->
    <h1 class="h2">COLOR</h1>   <!--Color changed-->
    <h1 class="h3">COLOR</h1>   <!--Color changed-->
    <h1 class="h1">COLOR</h1>   <!--Color changed-->
    <h1 class="h2">COLOR</h1>   <!--Color changed-->
    <h1 class="h3">COLOR</h1>   <!--Color changed-->

Comments

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.