Search code examples
jqueryperformanceresponsive-designgridster

Efficient way of using window.resize (or other method) to fire jquery functions, and making gridster.js repsonsive


I have been tinkering with some thoughts on a round-about way of making gridster.js responsive. I found a code snippit in the github issues in gridster and realized if I ran it under certain window sizing and destroyed and re-ran gridster I can get the effect of gridster responding responsivley. Let me show you what I mean -

$(window).resize(function(){
            var width = $(window).width();
            var columns = "";

            if(Modernizr.mq('screen and (max-width:640px)')){
                columns = 1;
                gridster.destroy();
                var tooFar = $('.gridster .gs-w').filter(function () {
                  return $(this).data('col') > columns;
                });
                $(tooFar).each(function () {
                  $(this).attr('data-col', '1');    
                });

                var tooBig = $('.gridster li').filter(function () {
                  return $(this).data('sizex') > columns;
                });
                $(tooBig).each(function () {
                  $(this).attr('data-sizex', columns);

                });
                $(".gridster ul").gridster({
                    widget_base_dimensions: [300, 300],
                    widget_margins: [5, 5],  
                    max_cols: 1,
                      resize: {
                          enabled: true
                        },
                        draggable: {
                          handle: '.dragDiv'
                        },
                    serialize_params: function ($w, wgd) {              
                        return {
                            /* add element ID to data*/
                            id: $w.attr('id'),
                            /* defaults */
                            col: wgd.col,
                            row: wgd.row,
                            size_x: wgd.size_x,
                            size_y: wgd.size_y,
                           /* htmlContent: $($w).html() */
                        }
                    }
        }).data('gridster');
            }

        });

So when gridster should break into 1 column (it has a base of 4), it destroys and re runs with 1 column. This works surprisingly well, the issue is this is not a pretty way of achieving this. I am also not showing all the break points ( it breaks into, 3 -2 -1 columns based on window size). It runs very poorly because its firing on every window resize, and I'm wondering if there is a cleaner way to do this where the functions would only fire once when they hit the window size.

Also - this is only to size gridster down, so if you size out it will not expand, I have not tried building those functions yet.

Any pointers or suggestions in using something that maybe isn't listening to every single instance of a window re-size would be super helpful.

Thanks!!


Solution

  • I gather from your question that gridster is being re-run continuously as the user resizes the window; that is, if you resize the window by dragging the window slowly, pixel by pixel, there is a gridster re-run for every pixel change.

    Try throttling the resize event with setTimeout. When resize fires, you set a timer to do the re-run of gridster -- say the timer duration is 200ms. If within that 200ms, another resize fires, you reset the timer. With this approach, the re-run only occurs when the user is done resizing (at least for the moment). You can tweak the timer duration for a better experience.

    Try:

    var resizeTimeout;
    $(window).resize(function(){
      if(!!resizeTimeout){ clearTimeout(resizeTimeout); }
      resizeTimeout = setTimeout(function(){
        //do gridster re-run here
      },200);
    });
    

    example fiddle (look at the console as you slowly resize the window)


    EDIT: For anyone interested in this pattern, I've extracted the throttling logic from the above code and put it into a jQuery plugin:

    (function($){
        $.fn.onDelayed = function(eventName,delayInMs,callback){
            var _timeout;
            this.on(eventName,function(e){
              if(!!_timeout){ 
                  clearTimeout(_timeout); 
                  console.log('timer being re-set: ' + eventName);
              } else {
                  console.log('timer being set for the first time: ' + eventName);
              }
              _timeout = setTimeout(function(){
                  callback(e);
              },delayInMs);
            });
        };
    })(jQuery);
    

    which would be used like

    $(function(){
        $(document).onDelayed('click',500,function(){
            alert('clicking is done');
        });
        $(window).onDelayed('resize',1000,function(){
            alert('resize is finished');
        });
    });
    

    Fiddle with two example uses of onDelayed