Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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;
}
like image 686
BlueDogRanch Avatar asked Oct 14 '20 21:10

BlueDogRanch


People also ask

How does window localStorage work?

localStorage is a property that allows JavaScript sites and apps to save key-value pairs in a web browser with no expiration date. This means the data stored in the browser will persist even after the browser window is closed.

When localStorage gets cleared?

localStorage is similar to sessionStorage , except that while localStorage data has no expiration time, sessionStorage data gets cleared when the page session ends — that is, when the page is closed.

What is localStorage in html?

Local storage is mainly used to store and retrieve data in HTML pages from the same domain. Even after restarting a browser, the data can be recovered from all windows in the same domain. This type of storage offers numerous options for Web apps.


1 Answers

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.

like image 137
johannchopin Avatar answered Oct 18 '22 01:10

johannchopin