JQuery: How to call RESIZE event only once it's FINISHED resizing?

JavascriptJqueryHtml

Javascript Problem Overview


How do I call a function once the browser windows has FINISHED resizing?

I'm trying to do it like so, but am having problems. I'm using the JQuery Resize event function:

$(window).resize(function() {
  ... // how to call only once the browser has FINISHED resizing?
});

However, this function is called continuously if the user is manually resizing the browser window. Which means, it might call this function dozens of times in short interval of time.

How can I call the resize function only a single time (once the browser window has finished resizing)?

UPDATE

Also without having to use a global variable.

Javascript Solutions


Solution 1 - Javascript

Here is an example using thejh's instructions

You can store a reference id to any setInterval or setTimeout. Like this:

var loop = setInterval(func, 30);

// some time later clear the interval
clearInterval(loop);

Solution 2 - Javascript

Debounce.

function debouncer( func , timeout ) {
   var timeoutID , timeout = timeout || 200;
   return function () {
      var scope = this , args = arguments;
      clearTimeout( timeoutID );
      timeoutID = setTimeout( function () {
          func.apply( scope , Array.prototype.slice.call( args ) );
      } , timeout );
   }
}


$( window ).resize( debouncer( function ( e ) {
    // do stuff 
} ) );

Note, you can use this method for anything you want to debounce (key events etc).

Tweak the timeout parameter for optimal desired effect.

Solution 3 - Javascript

You can use setTimeout() and clearTimeout() in conjunction with jQuery.data:

$(window).resize(function() {
    clearTimeout($.data(this, 'resizeTimer'));
    $.data(this, 'resizeTimer', setTimeout(function() {
        //do something
        alert("Haven't resized in 200ms!");
    }, 200));
});

Update

I wrote an extension to enhance jQuery's default on (& bind)-event-handler. It attaches an event handler function for one or more events to the selected elements if the event was not triggered for a given interval. This is useful if you want to fire a callback only after a delay, like the resize event, or else. https://github.com/yckart/jquery.unevent.js

;(function ($) {
    var methods = { on: $.fn.on, bind: $.fn.bind };
    $.each(methods, function(k){
        $.fn[k] = function () {
            var args = [].slice.call(arguments),
                delay = args.pop(),
                fn = args.pop(),
                timer;

            args.push(function () {
                var self = this,
                    arg = arguments;
                clearTimeout(timer);
                timer = setTimeout(function(){
                    fn.apply(self, [].slice.call(arg));
                }, delay);
            });

            return methods[k].apply(this, isNaN(delay) ? arguments : args);
        };
    });
}(jQuery));

Use it like any other on or bind-event handler, except that you can pass an extra parameter as a last:

$(window).on('resize', function(e) {
    console.log(e.type + '-event was 200ms not triggered');
}, 200);

http://jsfiddle.net/ARTsinn/EqqHx/

Solution 4 - Javascript

var lightbox_resize = false;
$(window).resize(function() {
    console.log(true);
    if (lightbox_resize)
        clearTimeout(lightbox_resize);
    lightbox_resize = setTimeout(function() {
        console.log('resize');
    }, 500);
});

Solution 5 - Javascript

Just to add to the above, it is common to get unwanted resize events because of scroll bars popping in and out, here is some code to avoid that:

function registerResize(f) {
    $(window).resize(function() {
        clearTimeout(this.resizeTimeout);
        this.resizeTimeout = setTimeout(function() {
            var oldOverflow = document.body.style.overflow;
            document.body.style.overflow = "hidden";
            var currHeight = $(window).height(),
                currWidth = $(window).width();
            document.body.style.overflow = oldOverflow;

            var prevUndefined = (typeof this.prevHeight === 'undefined' || typeof this.prevWidth === 'undefined');
            if (prevUndefined || this.prevHeight !== currHeight || this.prevWidth !== currWidth) {
                //console.log('Window size ' + (prevUndefined ? '' : this.prevHeight + "," + this.prevWidth) + " -> " + currHeight + "," + currWidth);
                this.prevHeight = currHeight;
                this.prevWidth = currWidth;

                f(currHeight, currWidth);
            }
        }, 200);
    });
    $(window).resize(); // initialize
}

registerResize(function(height, width) {
    // this will be called only once per resize regardless of scrollbars changes
});

see jsfiddle

Solution 6 - Javascript

Underscore.js has a couple of great methods for this task: throttle and debounce. Even if you're not using Underscore, take a look at the source of these functions. Here's an example:

var redraw = function() {'redraw logic here'};
var debouncedRedraw = _.debounce(redraw, 750);
$(window).on('resize', debouncedRedraw);

Solution 7 - Javascript

This is my approach:

document.addEventListener('DOMContentLoaded', function(){
    var tos = {};
    var idi = 0;
    var fn  = function(id)
    {
        var len = Object.keys(tos).length;
    
        if(len == 0)
            return;

        to = tos[id];
        delete tos[id];
    
        if(len-1 == 0)
            console.log('Resize finished trigger');
    };

    window.addEventListener('resize', function(){
        idi++;
        var id = 'id-'+idi;
        tos[id] = window.setTimeout(function(){fn(id)}, 500);
    });
});

The resize-event-listener catches all incoming resize calls, creates a timeout-function for each and saves the timeout-identifier along with an iterating number prepended by 'id-' (to be usable as array key) in the tos-array.

each time, the timout triggers, it calls the fn-function, that checks, if that was the last timeout in the tos array (the fn-function deletes every executed timout). if true (= if(len-1 == 0)), the resizing is finished.

Solution 8 - Javascript

jQuery provides an off method to remove event handler

$(window).resize(function(){
    if(magic == true) {
        $(window).off('resize', arguments.callee);
    }
});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionnickbView Question on Stackoverflow
Solution 1 - JavascriptZevanView Answer on Stackoverflow
Solution 2 - JavascriptBGerrissenView Answer on Stackoverflow
Solution 3 - JavascriptyckartView Answer on Stackoverflow
Solution 4 - JavascriptJlisView Answer on Stackoverflow
Solution 5 - JavascriptkofifusView Answer on Stackoverflow
Solution 6 - Javascripttybro0103View Answer on Stackoverflow
Solution 7 - JavascriptlsblsbView Answer on Stackoverflow
Solution 8 - JavascriptQiangView Answer on Stackoverflow