2

I create plugin something like this

timer plugin

(function($) {

    $.fn.timer = function(options) {

        var defaults = {
            seconds: 60
        };

        var options = $.extend(defaults, options);

        return this.each(function() {
            var seconds = options.seconds;
            var $this = $(this);

            var timerIntval;

            var Timer =  {
                setTimer : function() {
                    clearInterval(timerIntval);
                    if(seconds <= 0) {
                        alert("timeout");
                    }else {
                        timerIntval = setInterval(function(){
                            return Timer.getTimer();
                        }, 1000);
                    }
                },
                getTimer : function () {
                    if (seconds <= 0) {
                        $this.html("0");
                    } else {
                        seconds--;
                        $this.html(seconds);
                    }
                }
            }

            Timer.setTimer();
        });
    };
})(jQuery);

and I call the plugin like this.

$(".myTimer").timer({
    seconds : 100
});

i called the plugin at timerpage.php. When i changed the page to xxx.php by clicking another menu, the timer interval is still running and i need to the clear the timer interval.

i created a webpage using jquery ajax load. so my page was not refreshing when i change to another menu.

my question is, how to clear the timer interval or destroy the plugin when i click another menu?

Willyanto Halim
  • 413
  • 1
  • 6
  • 19
  • 1
    If the JS doesn’t reset when changing the page URL, then it seems you’re using the History API (`pushState`). Then you can use the `popstate`, `pagehide` or `pageshow` event to detect this. – Sebastian Simon Jan 11 '17 at 09:11
  • the js doesn't reset the url, it just changed the div content only when changing page.. could you be more spesific? @Xufox – Willyanto Halim Jan 11 '17 at 09:15
  • so, whenever you are changing the div content; i will suggest you to clear the previously created interval. – vijayP Jan 11 '17 at 09:16
  • so how to clear the created interval? @vijayP – Willyanto Halim Jan 11 '17 at 09:20
  • ok..let me add answer for this. Give me some time. – vijayP Jan 11 '17 at 09:25
  • @WilliamChandra _“[T]he [JS] doesn't reset the [URL]”_… that’s not what I said. When you change the URL (the location) of a page (by hand, via JS, with whatever technology), the JavaScript itself should reset. This includes any timeouts. You said _“When [I] changed the page to `xxx.php` by clicking another menu”_, so I assume you actually navigate to a completely distinct document, thus changing the location. This should automatically reset any timeouts, unless you use the History API or it’s not actually `timerpage.php` vs. `xxx.php` but actually `samepage.php#menuA` vs. `samepage.php#menuB`. – Sebastian Simon Jan 11 '17 at 10:12

2 Answers2

1

Instead of var timerIntval; set the variable timerInterval on the window object, then you will have the access this variable until the next refresh.

window.timerIntval = setInterval(function() {

Then when the user clicks on any item menu you can clear it:

$('menu a').click(function() {
  clearInterval(window.timerIntval);
});

Live example (with multiple intervals)

$('menu a').click(function(e) {
  e.preventDefault();
  console.log(window.intervals);
  for (var i = 0; i < window.intervals.length; i++) {
    clearInterval(window.intervals[i]);    
  }
});

(function($) {

  $.fn.timer = function(options) {

    var defaults = {
      seconds: 60
    };

    var options = $.extend(defaults, options);

    return this.each(function() {
      if (!window.intervals) {
        window.intervals = [];  
      }
      
      var intervalId = -1;
      var seconds = options.seconds;
      var $this = $(this);

      var Timer =  {
        setTimer : function() {           
          clearInterval(intervalId);
          if(seconds <= 0) {
            alert("timeout");
          } else {
            intervalId = setInterval(function(){
              //Timer.getTimer();
              return Timer.getTimer();
            }, 1000);
            window.intervals.push(intervalId);
          }
        },
        getTimer : function () {
          if (seconds <= 0) {
            $this.html("0");
          } else {
            seconds--;
            $this.html(seconds);
          }
        }
      }

      Timer.setTimer();
    });
  };
})(jQuery);

$(".myTimer").timer({
    seconds : 100
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<menu>
  <a href="#">Menu 1</a>
</menu>

<div class="myTimer"></div>
<div class="myTimer"></div>

Just notice that it's little bit risky because you can only run it once otherwise the interval id of the second will override the first.

Mosh Feu
  • 28,354
  • 16
  • 88
  • 135
  • The use of `.each()` tells me that this is incorrect. You'd need a plugin method that clears the interval, so that you can clear the interval from each element that's affected. – Reinstate Monica Cellio Jan 11 '17 at 09:26
  • @WilliamChandra I was updated my answer' it's working in my snippet. Keep attention that you should replace it in any `setInterval` function (there are 2 in your code) – Mosh Feu Jan 11 '17 at 09:28
  • sorry, you should change `return Timer.setTimer();` to `return Timer.getTimer();` – Willyanto Halim Jan 11 '17 at 09:30
  • @WilliamChandra ok. changed.. still working.. Any problem now? – Mosh Feu Jan 11 '17 at 09:37
  • Can you see that it works in my snippet? What is the difference between your code and mine? Can you create a snippet which reproduce the problem? – Mosh Feu Jan 11 '17 at 09:47
  • is it working for multiple element or class LIKE selector? because i load the jquery plugin in multiple element. – Willyanto Halim Jan 11 '17 at 10:20
  • `Just notice that it's little bit risky because you can only run it once otherwise the interval id of the second will overide the first.` - in my answer.. You can keep all the intervals in array, or you can "listen" in the plugin to [state change](http://stackoverflow.com/a/4585031/863110) then it will clear the interval by itself, or you can store it in the `.data` model just like in the @vijayP answer – Mosh Feu Jan 11 '17 at 10:26
  • you said i can keep all the intervals in array. so how to add the intervals array to window.timerIntval? – Willyanto Halim Jan 12 '17 at 02:08
  • You can push each interval to the array.. Something like: `window.intervals.push(theIntervalId)`. When user clicks on a link just loop on the array and call `clearInterval` for all of the items. – Mosh Feu Jan 12 '17 at 07:14
  • i dont get what you mean.. `window.timerIntval = setInterval(function(){ //Timer.getTimer(); return Timer.getTimer(); }, 1000); window.timerIntval.push(???)` – Willyanto Halim Jan 12 '17 at 07:17
  • No. `var interval = setInterval...` and then: `window.intervals.push(interval)`. I mean push the interval id into array on the window. The final goal is to keep array with all the ids. – Mosh Feu Jan 12 '17 at 07:20
  • i just dont understand using window object. it show `undefined window.intervals`. it's okay. i just follow @vijayP answer. thanks for your help and i'm very appreciate it. thankyou. – Willyanto Halim Jan 12 '17 at 07:45
1

Please try with following modifications:

timer plugin:

(function($) {

    $.fn.timer = function(options) {

        var defaults = {
            seconds: 60
        };

        var options = $.extend(defaults, options);

        return this.each(function() {
            var seconds = options.seconds;
            var $this = $(this);

            var timerIntval;

            var Timer =  {
                setTimer : function() {
                    clearInterval(timerIntval);
                    if(seconds <= 0) {
                        alert("timeout");
                    }else {
                        timerIntval = setInterval(function(){
                            return Timer.setTimer();
                        }, 1000);

                        $this.data("timerIntvalReference", timerIntval); //saving the timer reference for future use
                    }
                },
                getTimer : function () {
                    if (seconds <= 0) {
                        $this.html("0");
                    } else {
                        seconds--;
                        $this.html(seconds);
                    }
                }
            }

            Timer.setTimer();
        });
    };
})(jQuery);

Now in some other JS code which is going to change the div content

var intervalRef = $(".myTimer").data("timerIntvalReference"); //grab the interval reference
clearInterval(intervalRef); //clear the old interval reference

//code to change the div content on menu change

For clearing timer associated with multiple DOM element, you may check below code:

//iterate ovel all timer element:
$("h3[class^=timer]").each(function(){
    var intervalRef = $(this).data("timerIntvalReference"); //grab the interval reference
    clearInterval(intervalRef);
});

Hope this will give an idea to deal with this situation.

vijayP
  • 11,432
  • 5
  • 25
  • 40
  • it works for this case, but i have so many classes in my case.. `

    ` etc. so how can i call the element? i do something like this, but its not working. `$("h3[class^=timer]").data("timerIntvalReference")`

    – Willyanto Halim Jan 11 '17 at 10:10
  • `$("h3[class^=timer]")` will return you a list of object. To clear interval associated with them; you will have iterate over them as shown in updated answer. – vijayP Jan 11 '17 at 10:14
  • so i must declare it one by one? – Willyanto Halim Jan 11 '17 at 10:15
  • no..thats not mandatory. Actually `$.data()` method try to give you data saved for any particular DOM element. You may try above updated code and I am sure it will work for you. Let me know. – vijayP Jan 11 '17 at 10:23
  • what if i have multiple interval variabel? i tried to use this script, but it's not working.. `$(".myTimer").data("timerIntvalReference", { "var1" : timerIntval, "var2" : timerIntval });` and i call the `timerReference` like this `clearinterval($(".myTimer").data("timerIntvalReference").var1)`. but it showed error something like `undefined var1` – Willyanto Halim Jan 12 '17 at 07:23
  • `$this.data("timerIntvalReference", timerIntval);` is happening in plugin context. That is it is happening per DOM element. Where you are writing `$(".myTimer").data("timerIntvalReference", { "va`? Please provide complete code. Otherwise its difficult to locate the issue. – vijayP Jan 12 '17 at 07:37
  • `$(".myTimer").data("timerIntvalReference", { "var1" : timerIntval, "var2" : timerIntval2 });` – Willyanto Halim Jan 12 '17 at 07:42