Why does reading localStorage values require a page refresh to show CSS changes toggled by jQuery?

355 views Asked by At

I'm trying to use the value of localStorage to display one of two Twitter feeds, one for a light mode theme, the other for dark mode. It works, but I have to refresh the webpage for the correct CSS - either twitter-dark-display-none or twitter-light-display-none - to work.

Using jQuery(document).ready(function () doesn't help.

The Fiddle: https://jsfiddle.net/zpsf5q3x/2/ But the sample tweets don't show due to JSFiddle limits on displaying third party frames. And, localstorage may not work there, either.

Fiddle calls two external libraries: https://cdn.jsdelivr.net/gh/gitbrent/[email protected]/css/bootstrap4-toggle.min.css and https://cdn.jsdelivr.net/gh/gitbrent/[email protected]/js/bootstrap4-toggle.min.js

HTML:

Note the data-theme="dark" in the first block.

<div class="twitter-dark-display-none">
<a class="twitter-timeline" data-width="170" data-height="200" data-theme="dark"
 data-tweet-limit="1" data-chrome="transparent nofooter noborders" href="https://twitter.com/StackOverflow?ref_src=twsrc%5Etfw">Tweets</a>
</div>

<div class="twitter-light-display-none">
<a class="twitter-timeline" data-width="170" data-height="200" data-tweet-limit="1" data-chrome="transparent nofooter noborders" href="https://twitter.com/StackOverflow?ref_src=twsrc%5Etfw">Tweets</a>
</div>

jQuery:

Overall function that uses localStorage to toggle the entire site between dark and normal mode.

$('body').toggleClass(localStorage.toggled);
function darkLight() {
  if (localStorage.toggled != 'dark') {
    $('body').toggleClass('dark', true);
    localStorage.toggled = "dark";
  } else {
    $('body').toggleClass('dark', false);
    localStorage.toggled = "";
  }
}

What I'm trying to use to toggle CSS:

  if (localStorage.toggled === 'dark') {
    
        $('.twitter-light-display-none').addClass("display-none");
        $('.twitter-dark-display-none').addClass("display-block");
    
      } else {
    
        $('.twitter-dark-display-none').addClass("display-none");
        $('.twitter-light-display-none').addClass("display-block");
    
    }

CSS:

.display-none {
    display: none !important;
}

.display-block {
    display: block !important;
}

Edit 10/24/2020:

johannchopin's answer works, with the addition of $('body').toggleClass(localStorage.toggled); as in my original code above.

But. There is some sort of conflict with the gitbrent dark mode JS and CSS libraries, so I switched to https://github.com/coliff/dark-mode-switch and that results in a simpler way to both toggle dark mode and use localstorage in addition to the function johannchopin provided to switch between twitter widget divs:

<script>

(function() {
  var darkSwitch = document.getElementById("darkSwitch");
  if (darkSwitch) {
    initTheme();
    darkSwitch.addEventListener("change", function(event) {
      resetTheme();
    });
    function initTheme() {
      var darkThemeSelected =
        localStorage.getItem("darkSwitch") !== null &&
        localStorage.getItem("darkSwitch") === "dark";
      darkSwitch.checked = darkThemeSelected;
      darkThemeSelected
        ? document.body.setAttribute("data-theme", "dark")
        : document.body.removeAttribute("data-theme");
    }
    function resetTheme() {
      if (darkSwitch.checked) {
        document.body.setAttribute("data-theme", "dark");
        localStorage.setItem("darkSwitch", "dark"); 
} else {
        document.body.removeAttribute("data-theme");
        localStorage.removeItem("darkSwitch");  
      }
  updatedarkSwitch();
    }
  }
})();

function updatedarkSwitch() {
  if (localStorage.darkSwitch === 'dark') {
    $('.twitter-light-display-none').addClass("display-none").removeClass('display-block');
    $('.twitter-dark-display-none').addClass("display-block").removeClass('display-none');
  } else {
    $('.twitter-dark-display-none').addClass("display-none").removeClass('display-block');
    $('.twitter-light-display-none').addClass("display-block").removeClass('display-none');
  }
}
updatedarkSwitch()
</script>

And then use the most basic dark mode rule in the style sheet:

[data-theme="dark"] {
background-color: #000000 !important;
}

and also add any other more specific CSS rules needed, i.e.

[data-theme="dark"] .post-title{
color:#fff !important;
}
2

There are 2 answers

9
johannchopin On BEST ANSWER

You have multiple issues in you code. First, you toggle the CSS, but only when the page loads because this code is only run once (when the script is loaded):

if (localStorage.toggled === 'dark') {
  // ...

Just move this script in the function (ex: updateInterfaceTheme) that you call at the end of darkLight().

Another issue is that you forget to clean the previous class and that leads to a styling conflict:

$('.twitter-light-display-none').addClass("display-none"); // class .display-block still exist
$('.twitter-dark-display-none').addClass("display-block"); // class .display-none still exist

So don't forget to clean them:

 if (localStorage.toggled === 'dark') {
    $('.twitter-light-display-none').addClass("display-none").removeClass('display-block');
    $('.twitter-dark-display-none').addClass("display-block").removeClass('display-none');
  } else {
    $('.twitter-dark-display-none').addClass("display-none").removeClass('display-block');
    $('.twitter-light-display-none').addClass("display-block").removeClass('display-none');
  }

And like that it's working:

function darkLight() {
  if (localStorage.toggled !== 'dark') {
    $('body').toggleClass('dark', true);
    localStorage.toggled = "dark";
  } else {
    $('body').toggleClass('dark', false);
    localStorage.toggled = "";
  }

  updateInterfaceTheme();
}

function updateInterfaceTheme() {
  if (localStorage.toggled === 'dark') {
    $('.twitter-light-display-none').addClass("display-none").removeClass('display-block');
    $('.twitter-dark-display-none').addClass("display-block").removeClass('display-none');
  } else {
    $('.twitter-dark-display-none').addClass("display-none").removeClass('display-block');
    $('.twitter-light-display-none').addClass("display-block").removeClass('display-none');
  }
}

updateInterfaceTheme()
.display-none {
  display: none !important;
}

.display-block {
  display: block !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<label class="switch"><span class="switchtext">Dark</span>
  <input type="checkbox" data-style="ios" data-onstyle="outline-secondary" data-offstyle="outline-secondary" data-size="sm" data-toggle="toggle" onchange="darkLight()">
  <span class="slider"></span><span class="switchtext">Mode</span>
</label>

<div class="twitter-dark-display-none">Dark Mode
  <a class="twitter-timeline" data-width="170" data-height="200" data-theme="dark" data-tweet-limit="1" data-chrome="transparent nofooter noborders" href="https://twitter.com/StackOverflow?ref_src=twsrc%5Etfw">Tweets</a>
</div>

<div class="twitter-light-display-none">Light Mode
  <a class="twitter-timeline" data-width="170" data-height="200" data-tweet-limit="1" data-chrome="transparent nofooter noborders" href="https://twitter.com/StackOverflow?ref_src=twsrc%5Etfw">Tweets</a>
</div>

Checkout the jsfiddle to see it working with localStorage.

1
ddd.foster On

You should use method getItem().

let x = localStorage.getItem('toggled');

And than make a check for a variable.


https://developer.mozilla.org/ru/docs/Web/API/Storage/getItem