JS setInterval variable scope

So, I have this abomination:

$(".toasted").on("click", function (e) {

        var btn_id = $(this).attr('id');

        storeInLocalStorage('btnIDS', btn_id);

        var interval = 5 * 1000;

        timer = '';

        function reset() {
            localStorage.setItem("endTime"+btn_id, +new Date + interval);
        }

        if (!localStorage.getItem("endTime"+btn_id)) {
            reset();
        }

        setInterval(function () {

            var remaining = localStorage.getItem("endTime"+btn_id) - new Date;

            $('#'+btn_id).prop('disabled', true);

            if (remaining >= 0) {
                timer = Math.floor(remaining / 1000);
            } else {
                $('#toast_'+btn_id).html('');
                localStorage.removeItem("endTime"+btn_id);
                removeFromLocalStorage(btn_id);
                $('#'+btn_id).prop('disabled', false);
                reset();
            }
        }, 100);

        $.toast({
            id: '#toast_'+btn_id,
            type: 'primary',
            title: 'what a bullshit this is!',
            subtitle: timer + "s",
            content: 'hello',
            delay: timer,
            icon: "fa-solid fa-list-check", // font-awesome6 icon class
        });
});

Variable "timer" does not get updated in setInterval function... I guess this is due to scope. But I tried everything. Inside, outside, var, let etc. Nothing helps. Either it is 0 or undefined. Can someone help me here?

Comments

  • bikegremlinbikegremlin ModeratorOGContent Writer

    ChatGPT says this:

    The issue in your code seems to be related to how and when you're updating and using the timer variable, especially within the scope of the setInterval function and when you're trying to use it in the $.toast call. The timer variable's value is being set asynchronously inside the setInterval function, which means its value when passed to $.toast is not the updated one because $.toast is called immediately after setting the interval, not waiting for the interval to update the timer.

    To address the problem, you need to update the toast message dynamically within the interval callback to reflect the current timer value. However, it seems like the $.toast plugin or method you're using may not support updating an existing toast message directly based on the API call you've shown. If $.toast does not support dynamic updates, you might need to look for alternative methods to achieve this, like manually updating the DOM element representing the toast or finding a toast library that supports dynamic updates.

    Here is an approach to fix the issue based on assumptions about how your toast system works. This code assumes you need to create a new toast or update an existing one dynamically:


    The code robot provided:

    https://wtools.io/paste-code/bTX0


    Please note, this solution assumes you have a way to dynamically update or manage toast messages via $.toast. If your actual toast plugin or library doesn't support dynamically updating existing toasts, you may need to manually manage the toast content or look for a toast library that supports this feature.

    If $.toast cannot update an existing toast, you might need to destroy the old toast and create a new one on each update or directly manipulate the DOM to change the toast message. Check your toast plugin's documentation for methods to update or manage toasts dynamically.

    Relja of House Novović, the First of His Name, King of the Plains, the Breaker of Chains, WirMach Wolves pack member
    BikeGremlin's web-hosting reviews

  • edited March 6

    You're correct; the timer variable doesn't get updated inside the setInterval function because the setInterval function captures the value of timer at the time it's created, and subsequent changes to timer won't affect the behavior of the interval.

    To ensure that the timer value updates within the setInterval function, you can move the $.toast function call inside the setInterval function. This way, the timer value will be recalculated each time the setInterval function executes. Here's the revised code:

    $(".toasted").on("click", function (e) {
        var btn_id = $(this).attr('id');
        storeInLocalStorage('btnIDS', btn_id);
        var interval = 5 * 1000;
    
        function reset() {
            localStorage.setItem("endTime"+btn_id, +new Date() + interval);
        }
    
        if (!localStorage.getItem("endTime"+btn_id)) {
            reset();
        }
    
        setInterval(function () {
            var remaining = localStorage.getItem("endTime"+btn_id) - new Date();
    
            $('#'+btn_id).prop('disabled', true);
    
            var timer = ''; // Declare timer variable here
    
            if (remaining >= 0) {
                timer = Math.floor(remaining / 1000);
            } else {
                $('#toast_'+btn_id).html('');
                localStorage.removeItem("endTime"+btn_id);
                removeFromLocalStorage(btn_id); // Make sure removeFromLocalStorage is defined
                $('#'+btn_id).prop('disabled', false);
                reset();
            }
    
            // Display toast message within setInterval
            $.toast({
                id: '#toast_'+btn_id,
                type: 'primary',
                title: 'what a bullshit this is!',
                subtitle: timer + "s",
                content: 'hello',
                delay: timer * 1000, // Delay should be in milliseconds
                icon: "fa-solid fa-list-check", // font-awesome6 icon class
            });
    
        }, 100);
    });
    

    By declaring the timer variable inside the setInterval function, it will be updated each time the interval executes, reflecting the correct timer value in the toast message.

    Best Regards,

    ChatGPT

  • Nice. But chatGPT does not know that $.toast() function launches new instance of toast. So, each 100ms it launches new toast...

  • somiksomik OG
    edited March 6

    What are you trying to do? If you say timer does not get updated, then just declare it outside as a "var".

    var timer = 0;
    
    $(".toasted").on("click", function (e) {
        // other shit goes here
    }
    

    Also provide a https://jsfiddle.net/ example of what you are trying to do so we can help better.

    Artificial intelligence is no match for our natural stupidity.

    Time flies like an arrow; fruit flies like a banana.

  • bikegremlinbikegremlin ModeratorOGContent Writer

    @legendary said:
    Nice. But chatGPT does not know that $.toast() function launches new instance of toast. So, each 100ms it launches new toast...

    Robot says: :)

    You're right, and I appreciate the clarification. If $.toast() launches a new instance each time it's called, then calling it every 100ms within the setInterval function, as suggested, would indeed create a new toast notification every 100ms, which is not the intended behavior.

    To avoid spamming the user with new toast messages, you should manage the visibility or update the content of an existing toast notification rather than creating a new one on each interval tick. Given the information about how $.toast() works, here's an adjusted approach:

    Option 1: Check if a toast is already visible before showing a new one. This would require knowing how to check the visibility or existence of a toast instance, which depends on the specific toast library you're using.

    Option 2: Update the toast if possible. If the library supports updating an existing toast, use that functionality. It sounds like this might not be supported in your case.

    Option 3: Manually manage toast visibility. Keep track of whether a toast is currently shown and manually manage its content if the library allows, or remove the old toast before showing a new one if removal is supported.

    Since creating a new toast every 100ms isn't feasible, let's adjust the approach to avoid creating multiple instances unnecessarily. Without the ability to update an existing toast directly and lacking specific support in your toast library for this action, the best approach might be to limit toast creation to situations where it's necessary (e.g., only when the timer updates significantly or when you first create the toast and after the timer expires).

    Here's a simplified concept that avoids creating a toast within the setInterval:


    The code it gave:

    https://wtools.io/paste-code/bTX2


    This approach assumes you can either update the toast dynamically with a function like updateOrCreateToast (which you would need to implement based on your library's capabilities) or you choose to show the toast only when necessary and remove it when done, using removeToast.

    Without specifics on the toast library's API and its capabilities for updating or managing existing toasts, the implementation details for updateOrCreateToast and removeToast will vary. Check your library's documentation for the appropriate methods to accomplish these tasks.

    Relja of House Novović, the First of His Name, King of the Plains, the Breaker of Chains, WirMach Wolves pack member
    BikeGremlin's web-hosting reviews

  • Now, I had a nice and long chat with GPT. And we came to the half working solution:

    https://jsfiddle.net/vo0mhgf7/

    The problem: values set in localStorage are deleted after page refresh. GPT can't help here as it offers solutions which does not fix the problem. My web browser saves localStorage, also I have test with sessionStorage. Same shit. Does anyone knows why this part does not work?

    $(document).ready(function() {
      recreateToasts();
    });
    
  • Ha, finally we came to the solution. If anyone needs it: https://jsfiddle.net/u6qsf2t5/

  • If you want the info to retain a page refresh, use cookies. JS can access/read/write cookies.

    Artificial intelligence is no match for our natural stupidity.

    Time flies like an arrow; fruit flies like a banana.

Sign In or Register to comment.