0

Before posting this I've browsed some existing topics but couldn't get anything helpful, I tried some things to fix this but it failed.

I'm developing a website, and today I wanted to code a basic dark mode switch in Javascript :

<script type="text/javascript">
function switchWhite() {
    document.getElementById("body").className = "";
    document.getElementById("menubar").className = "navbar navbar-expand-lg navbar-light bg-light";
}

function switchDark() {
    document.getElementById("body").className = "dark";
    document.getElementById("menubar").className = "navbar navbar-expand-lg navbar-dark bg-dark";
}

function triggerSwitch() {
    if ( document.getElementById("body").className.match("dark") ) {
        switchWhite();
    } else {
        switchDark();
    }
}
</script>

<button onclick="triggerSwitch()">Switch Mode</button>

This works just fine but there is an auto-refresh on the website, which is triggered every 30 seconds and which refreshes only specific blocs (like menubar) :

<script>
setInterval(function()
{
    $(document).ready(function() {
        $("#menubar_refresh").load(document.URL + " #menubar");
    });
}, 30000);
</script>

Which also works fine, but I cannot mix these two features because once I switch to dark mode theme, after 30 seconds (when the auto-refresh is triggered), it gets back to light mode (the original state of the page).

Though is this normal, so I tried to put the dark mode back right after the bloc refreshes, like this :

<script>
setInterval(function()
{
    $(document).ready(function() {
        $("#menubar_refresh").load(document.URL + " #menubar");
    });
    switchDark(); // here
}, 30000);
</script>

It simply doesn't work, the bloc (and only this bloc, not the whole page) still gets back to the original state (light).
I've noticed that it switches to dark mode for a few milliseconds, and gets back to the original state.
I thought that the switchDark(); call is executed at first, even before the whole function finishes, in a way that the dark mode is set and then the bloc is refreshed.

So I tried setting a variable to block the execution of switchDark(); call before everything else finished executing, but the result is the same, which makes me think that my hypothesis is wrong.

Could you please help me to figure out what the problem is here ?
I can add more code snippets if you need them.

Thanks a lot

2 Answers 2

2

load() is asynchronous so you need to modify any new content in the complete callback.

Something like:

$("#menubar_refresh").load(document.URL + " #menubar", switchDark);

Or more verbose version:

$("#menubar_refresh").load(document.URL + " #menubar", function(){
    // new content now exists
    // add logic as to which theme method to call
    if(isDark){
      switchDark();
    }
});
Sign up to request clarification or add additional context in comments.

1 Comment

Well, this works. I don't know why I didn't think about it, thanks a lot.
0

So, I'm in agreement with the answer by @charlietfl. But there is a flaw in your code due to misunderstanding and misinterpretation of javascript's event handler asynchronous nature.

The code in question is this:

<script> 
    setInterval(function() { 
        $(document).ready(function() { 
            $("#menubar_refresh").load(document.URL + " #menubar"); }); 
            switchDark(); // here 
        }, 
    30000);
</script>

You are using $(document).ready inadvertently as an if statement not as an event handler. Apparently, your code says after 30secs, if the document is ready, refresh the document and switch to a dark theme. But actually, your code means after 30secs, attach the ready state change handler to document. In this handler, asynchronously refresh the page and [immediately] switch to a dark theme.

Now, here lies your problem:

  1. Though there is practically one, there is no 'absolute' guarantee that the document will be ready after 30secs. Consequently, your code setup isn't one that actually executes after 30secs.
  2. There is no practical and absolute guarantee that the page will refresh completely before switchDark() executes. Why? The code for refreshing is asynchronous. Consequently, your switchDark() function almost never executes as you expect it to (though it always executes) since you expect it to use code from the newly loaded page.

A better and more meaningful code setup is to include setInterval inside $(document).ready handler and use a callback with the load() method for any code you want executed after the load() method.

<script> 
    $(document).ready(function() { 
        setInterval(function() { 
            $("#menubar_refresh").load(document.URL + " #menubar", function() {
                switchDark(); // here 
            }); 
        }, 30000);
    });
</script>

2 Comments

load() does not return a deferred object
@charlietfl, thanks for pointing that out. I've corrected that. My major point is the position of $('document').ready in the question.

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.