5

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!!

ajmajmajma
  • 13,712
  • 24
  • 79
  • 133

1 Answers1

16

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

Jonathan Wilson
  • 4,138
  • 1
  • 24
  • 36
  • You're welcome! Did I answer your question fully, or is there something I didn't properly address? – Jonathan Wilson Jun 30 '14 at 00:02
  • 1
    Paul Irish uses debounce in similar fashion: http://www.paulirish.com/2009/throttled-smartresize-jquery-event-handler/ – ericslaw Mar 26 '15 at 19:45
  • 1
    For clarification, this pattern is called debouncing. The throttling pattern will allow calls between the start and end of an action, but only once per defined time period. Debouncing only performs the function a defined amount of time after the function was last called. – shamsup Jun 09 '17 at 21:03