Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get my Dark Mode switch to work on each click?

I'm building an app with a dark mode switch. It works on the first click, but after that, it works on every second click.

(this snippet shows a checkbox. In the project, it looks like a real switch)

Any idea how I can get it to work on a single click?

const body = document.getElementById('body');
let currentBodyClass = body.className;
const darkModeSwitch = document.getElementById('darkModeSwitch');

//Dark Mode
function darkMode() {
    darkModeSwitch.addEventListener('click', () => {
        if (currentBodyClass === "lightMode") {
            body.className = currentBodyClass = "darkMode";
        } else if (currentBodyClass === "darkMode") {
            body.className = currentBodyClass = "lightMode";
        }
    });
}
#darkModeSwitch {
        position: absolute;
        left: 15px;
        top: 15px;
    }

.darkMode { background-color: black; transition: ease .3s; }
.lightMode { background-color: #FFF; transition: ease .3s; }

#darkModeSwitch input[type="checkbox"] {
  width: 40px;
  height: 20px;
  background: #fff89d;
}

#darkModeSwitch input:checked[type="checkbox"] {
  background: #757575;
}

#darkModeSwitch input[type="checkbox"]:before {
  width: 20px;
  height: 20px;
  background: #fff;
}

#darkModeSwitch input:checked[type="checkbox"]:before {
  background: #000;
}
<body id="body" class="lightMode">

  <div id="darkModeSwitch">
     <input type="checkbox" onclick="darkMode()" title="Toggle Light/Dark Mode" />
  </div>

</body>
like image 232
PizzaCompany88 Avatar asked Jan 30 '20 14:01

PizzaCompany88


1 Answers

Every time you click on your checkbox, you're adding another eventListener to darkModeSwitch - Take your addEventListener out of the function and remove the onclick

Then, you need to move let currentBodyClass = body.className; inside the darkModeSwitch function, so that the value is updated each time. Having it outside the function, you're assigning it a value once at run time, and then never updating it

Finally, this makes limited sense

body.className = currentBodyClass = "darkMode";

Instead, just do

body.className = "darkMode";

const darkModeSwitch = document.getElementById('darkModeSwitch');
const body = document.getElementById('body');

//Dark Mode
darkModeSwitch.addEventListener('click', () => {
  let currentBodyClass = body.className;

  if (body.className === "lightMode") {
    body.className = "darkMode";
  } else if (currentBodyClass === "darkMode") {
    body.className = "lightMode";
  }
});
#darkModeSwitch {
  position: absolute;
  left: 15px;
  top: 15px;
}

.darkMode {
  background-color: black;
  transition: ease .3s;
}

.lightMode {
  background-color: #FFF;
  transition: ease .3s;
}

#darkModeSwitch input[type="checkbox"] {
  width: 40px;
  height: 20px;
  background: #fff89d;
}

#darkModeSwitch input:checked[type="checkbox"] {
  background: #757575;
}

#darkModeSwitch input[type="checkbox"]:before {
  width: 20px;
  height: 20px;
  background: #fff;
}

#darkModeSwitch input:checked[type="checkbox"]:before {
  background: #000;
}
<body id="body" class="lightMode">

  <div id="darkModeSwitch">
    <input type="checkbox" title="Toggle Light/Dark Mode" />
  </div>

</body>

Finally, you might want to consider using .classList when working with an Element's classes, as it will allow you to make use of methods such as .add() / .remove() / .contains() - Your current method will fail if the Element has more than one class set at a time, while these methods avoid this

let currentBodyClass = body.classList;

if (currentBodyClass.contains("lightMode")) {
  currentBodyClass.add('darkMode');
  currentBodyClass.remove('lightMode');
} else if (currentBodyClass.contains("darkMode")) {
  currentBodyClass.add('lightMode');
  currentBodyClass.remove('darkMode');
}
like image 191
Shiny Avatar answered Oct 24 '22 17:10

Shiny