Results 1 to 9 of 9

Thread: jQuery "wait" plugin (setInterval)

  1. #1
    Join Date
    Jan 2007
    Posts
    58
    Thanks
    11
    Thanked 0 Times in 0 Posts

    Default jQuery "wait" plugin (setInterval)

    Hi, I've made a plugin with lots of flaws (obviously) and I was wondering if you could help me out to make it perfect or close to it.

    I call this plugin from a page, which is accessed by a link using $.ajax to bring the contents dynamically.

    Code:
    (function($){
    $.fn.wait = function(options,callback){
    	var element = $(this);
    	var defaults = {
    		seconds: 60,
    		output: '',
    		left: '',
    		right: ''
    	}
    	if (options) { var options = $.extend(defaults, options); }
    	return this.each(function() {
    		var count = 0;
    		if (options.output != 'hidden') {
    			element.html(options.left + options.seconds + options.right);
    		}
    		function timer() {
    			count++
    			if (options.output != 'hidden') {
    				var rem = options.seconds-count;
    				var secHtml = options.left + rem + options.right;
    				element.html(secHtml);
    			}
    			if (count == options.seconds) {
    				clearInterval(element.timer);
    				if ($.isFunction(callback)){
    					callback.call(element);
    				}
    			}
    		}
    		element.timer = setInterval(timer, 1000);
    	});
    }})(jQuery);
    Now, the problem arrives when i click on the link to this page again. The page "refreshes" and the plugin is called again, problem is, it doesn't get to clear the interval, so now we have 2 simultaneous intervals.

    Question: How can I clear the first interval and leave only the second one running?

    Your help will be much appreciated guys.
    Thanks.
    Last edited by nicksalad; 12-07-2010 at 04:41 PM.

  2. #2
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    When $.ajax() is invoked, get a reference to $(element) if you don't already have one. Clear the interval then, if it exists. You might be able to use the:

    beforeSend

    function property of the request to either clear the interval or cancel the new request if
    the old one is still going on.

    If that won't work, do it before doing the $.ajax().


    A few things about the code - These have nothing to do with your question -

    1. Unlike jQuery functions, when using the jQuery constructor:


      Code:
      $.fn.whatever = function . . .
      this is already $(this), so the line:

      Code:
      	var element = $(this);
      could be:

      Code:
      	var element = this;
    2. If there are no options, there will be an error. You can do something like replacing:

      Code:
      	var defaults = {
      		seconds: 60,
      		output: '',
      		left: '',
      		right: ''
      	}
      	if (options) { var options = $.extend(defaults, options); }
      with:

      Code:
      	var defaults = {
      		seconds: 60,
      		output: '',
      		left: '',
      		right: ''
      	}
      	options = options || {};
      	options = $.extend(defaults, options);
    3. Pre-increment is more efficient than post-increment and can be used here:

      Code:
      		function timer() {
      			++count;
      			if (options.output != 'hidden') {
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  3. The Following User Says Thank You to jscheuer1 For This Useful Post:

    nicksalad (12-07-2010)

  4. #3
    Join Date
    Jan 2007
    Posts
    58
    Thanks
    11
    Thanked 0 Times in 0 Posts

    Default

    Thanks for your great reply, however, since im kinda noob, I am clueless about this part:

    When $.ajax() is invoked, get a reference to $(element) if you don't already have one. Clear the interval then, if it exists. You might be able to use the:

    beforeSend

    function property of the request to either clear the interval or cancel the new request if
    the old one is still going on.

    If that won't work, do it before doing the $.ajax().
    Can you give me an example of how to do this? Because the setInterval is added inside of the plugin like this:

    element.timer = setInterval(timer, 1000);

    where element.timer would be something like $('#element').timer right?

    So, how can I clear it from outside the plugin?

    Lets say, if the element im using is $('#element'), on the beforeSend should I do something like this?

    clearInterval($('#element').timer)

    I'm kinda lost about that part. Hope you can help me with my confusion hehe.

    Thank you John.

  5. #4
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    That's right. That's what I meant by:

    get a reference to $(element) if you don't already have one
    I meant also though, if you're passing control over to or just invoking the wait function from the $.ajax() function, when you do that - you must have a reference to the element at that point. Clear the interval then.

    Also, since you are talking about a property that might not exist, you may need to test for it:

    Code:
    if($('#element').timer){
    	clearInterval($('#element').timer);
    }
    I say may, because browsers will not throw an error on a missing property one level deep. But since you are trying to do something with it, and because jQuery is involved, it wouldn't hurt to test. I'd try it without the test first though, see if there are any error messages when it's used when you know there is none defined yet.

    Or, to conserve processing time, just define it once:

    Code:
    var el = $('#element');
    if(el.timer){
    	clearInterval(el.timer);
    }
    el.wait({seconds: 60, output: '', left: 'You Have ', right: ' Seconds to Live :-)'}, function(){return;});
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  6. The Following User Says Thank You to jscheuer1 For This Useful Post:

    nicksalad (12-08-2010)

  7. #5
    Join Date
    Jan 2007
    Posts
    58
    Thanks
    11
    Thanked 0 Times in 0 Posts

    Default

    Alright, I've tried both methods, my code looks like this:

    left_menu.php
    Code:
    <ul id="menuList">
    			<li><img src="images/bullet1.gif" class="imgMiddle"></img>&nbsp;&nbsp;<span class="clickable midContent" id="home.php"><?php echo $ll["home"]; ?></span></li>
    			<li><img src="images/bullet1.gif" class="imgMiddle"></img>&nbsp;&nbsp;<span class="clickable midContent" id="register.php"><?php echo $ll["signUp"]; ?></span></li>
    			<li><img src="images/bullet1.gif" class="imgMiddle"></img>&nbsp;&nbsp;<span class="clickable midContent" id="download.php"><?php echo $ll["download"]; ?></span></li>
    			<li><img src="images/bullet1.gif" class="imgMiddle"></img>&nbsp;&nbsp;<span class="clickable midContent" id="rankings.php"><?php echo $ll["rankings"]; ?></span></li>
    			<li><img src="images/bullet1.gif" class="imgMiddle"></img>&nbsp;&nbsp;<span class="clickable midContent" id="contact.php"><?php echo $ll["contactUs"]; ?></span></li>
    		</ul>
    fakeLinks plugin:
    Code:
    (function($){
    $.fn.fakeLinks = function(options,callback){
    	var defaults = {
    		trgt: 'div#midContent',
    		auth: ''
    	}
    	if (options) { var options = $.extend(defaults, options); }
    	
    	return this.each(function() {
    		var ax = 0;
    		$(this).unbind().click(function() {
    			ax++
    			if (ax == 1) {
    				var file = $(this).attr('id');
    				$(options.trgt).preloader(function() {
    					$(this).load('./include/' + file, { auth: options.auth }, function() {
    						if ($(this).height() > 300) {
    							$('#leftRanks').fadeIn();
    						} else {
    							$('#leftRanks').hide();
    						}
    						ax = 0;
    					});
    				});
    			}
    		});
    		
    		if ($.isFunction(callback)){
    			//callback.call(element,options.seconds);
    			callback.call(element);
    		}
    	});
    	
    }})(jQuery);
    register.php
    Code:
    	//Submit block
    	var waitSubmit = 0;
    	var el = $('#submitButtonInfo');
    	if (el.timer) {
    		clearInterval(el.timer); //Never clears it because it seems like at this point el.timer is never defined, even tho the interval is running...
    	}
    	el.wait({ seconds: <?php echo $cfg['submitSecs']; ?>, left: '(', right: ')' }, function(){
    		waitSubmit = 1;
    		$(this).html('');
    		submitButton();
    	});
    wait plugin:
    Code:
    (function($){
    $.fn.wait = function(options,callback){
    	var element = this;
    	var defaults = {
    		seconds: 60,
    		output: '',
    		left: '',
    		right: ''
    	}
    	if (options) { var options = $.extend(defaults, options); }
    	return this.each(function() {
    		var count = 0;
    		if (options.output != 'hidden') {
    			element.html(options.left + options.seconds + options.right);
    		}
    		function timer() {
    			++count
    			alert(element.timer); //This shows an int e.g: 215 and when clicked twice on register link, shows 2 pop ups, 215 and let's say 513.
    			if (options.output != 'hidden') {
    				var rem = options.seconds-count;
    				var secHtml = options.left + rem + options.right;
    				element.html(secHtml);
    			}
    			if (count == options.seconds) {
    				clearInterval(element.timer);
    				if ($.isFunction(callback)){
    					callback.call(element);
    				}
    			}
    		}
    		element.timer = setInterval(timer, 1000);
    	});
    }})(jQuery);
    It doesn't work, obviously I'm doing something wrong. The old interval is still there.
    Last edited by nicksalad; 12-08-2010 at 03:05 AM.

  8. #6
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    I'm not seeing any $.ajax() there. That could be the problem. If you're importing the element, then its timer pointer will be wiped out. It won't clear the interval, just lose the handle to the interval. If that's the case, then you have to set the interval equal to something that's not being overwritten. That way, when you later go to clear it, the handle will still be valid.

    Even if the element isn't being overwritten, the reference to the interval is being lost. With something like that one should use either the .data() function of jQuery:

    Code:
    element.data('timer', setInterval(timer, 1000));
    to set it, and to clear it:

    Code:
    if(el.data('timer')){
    	clearInterval(el.data('timer'));
    }
    Or, as I say, find some other object that's available in both scopes to attach the handle for the interval to. You could even use the global scope:

    Code:
    window.elementTimer = setInterval(timer, 1000);
    to set, and to clear:

    Code:
    clearInterval(window.elementTimer);
    With that, no test is required. All browsers will allow clearing a nonexistent property of the window object.

    To help more with this I pretty much need to see the live page.

    Please post a link to a page on your site that contains the problematic code so we can check it out.
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  9. The Following User Says Thank You to jscheuer1 For This Useful Post:

    nicksalad (12-08-2010)

  10. #7
    Join Date
    Jan 2007
    Posts
    58
    Thanks
    11
    Thanked 0 Times in 0 Posts

    Default

    I've tried both again, only the last one works, partially... because I got multiple instances by default on the same page, for example, I got this one for the submit button, which blocks it for 30 secs first (while you complete the form), and once you submit it, if there was a mistake, it blocks it again for 10 secs to prevent those annoying double clicks and also flooding. I have another interval set for the checking of availability of user id, they can check it as soon as they blur, but takes 5 secs after they blur, if it's taken, they change it and wait 5 secs again, and so on. So it must really be a dynamically set name, else it won't work for 2 or more instances running in parallel.

    Now, Question.. Can I set elementTimer dynamically? let's say:
    var dyna = 'elementTimer ';

    window.dyna = setInterval(timer, 1000);

    I know this doesn't work, but is there another way you can think of? Because if this works, I can pass an unique id to the plugin, let's say, for the submit button "submit" and for the userid "userIdCheck".

    Btw, sorry for the $.ajax thingie, I forgot it was a $.load instead... :/
    Last edited by nicksalad; 12-08-2010 at 09:50 AM.

  11. #8
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    OK, I found the $.load() and it is a call to $.ajax(), just by another name, for a more specific purpose and with a more limited subset of options. That might be why beforeSend doesn't work. It's not listed as an option for $.load().

    It's not clear to me if $('#submitButtonInfo') is getting overwritten or not. Even if it isn't, simply referencing it again might create it anew without the nonstandard .timer property.

    If the element is not getting overwritten, you could try attaching the timer to the element itself - to set:

    Code:
    element.get(0).timer = setInterval(timer, 1000);
    to clear:

    Code:
    	var el = $('#submitButtonInfo');
    	if (el.get(0).timer) {
    		clearInterval(el.get(0).timer);
    	}
    It's also not clear to me if 'element' in the code is even the same element as 'el' in the code.

    You can of course create a unique reference to each interval. But then you need a way of accessing the correct one when it comes time to clear it.

    Another approach could be to not allow any new intervals until the current one is finished.

    Anyways, I'm having trouble visualizing all of this. I think I need to see the page.

    Please post a link to a page on your site that contains the problematic code so we can check it out.
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  12. #9
    Join Date
    Jan 2007
    Posts
    58
    Thanks
    11
    Thanked 0 Times in 0 Posts

    Default

    Ok, I will set the dns, upload the files to the host and let u know when done, this shouldn't take more than 1 hour (resolving and all), however it's quite late here, 2:20am, so I will leave it for tom morning. Will let u know when done.

    Btw, I'm not sure if u can see the code tho, It's kinda hidden (JS hidden... lol).

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •