Tuesday 12 January 2016

Gridster.js: saving the state and dynamic loading of the elements

Gridster is a jQuery plugin that allows building intuitive draggable layouts from elements spanning multiple columns. You can even save the state of the elements and dynamically load the elements from the grid. Dynamic loading is on par with sliced bread, or possibly better.
          You all must be familiar with the new windows 8 theme. Here I am going to implement the Windows 8 theme (Although the functionalities would not be the same, the UI may look similar). If I would have got the same functionalities running, I would have been working at Microsoft now. :P
          Nevertheless, you will be able to use this theme as a web application. You might want to integrate this cool feature in your website.Trust me! Its a lot easier. This is where gridster comes into the picture. There are no articles as such which will provide you with the insights of Gridster.js. Since there are too many unsolved issues related to this topic, I thought of sharing my experience and this blog is intended to do so.

To know about the issues related with this plugin, you can go through the following link:
https://github.com/ducksboard/gridster.js/issues?page=1&state=open

Windows 8 Theme

Enough of Theory! Huh!!! Bored??? You must not be :P
Lets jump directly into the implementation part

Getting Started

index.html

<script type="text/javascript" src="assets/jquery.js"></script>
<script type="text/javascript" src="assets/jquery.gridster.js" charster="utf-8"></script>


HTML structure

<div class="gridster">
<ul id="hello">

<li id="li1" data-row="1" data-col="1" data-sizex="1" data-sizey="1"></li>
<li id="li2" data-row="2" data-col="1" data-sizex="1" data-sizey="1"></li>
<li id="li3" data-row="3" data-col="1" data-sizex="1" data-sizey="1"></li>
<li id="li4" data-row="4" data-col="1" data-sizex="2" data-sizey="1"></li>
<li id="li5" data-row="1" data-col="2" data-sizex="1" data-sizey="1"></li>
<li id="li6" data-row="2" data-col="2" data-sizex="1" data-sizey="1"></li>
<li id="li7" data-row="3" data-col="2" data-sizex="1" data-sizey="1"></li>

<li id="li8" data-row="1" data-col="3" data-sizex="2" data-sizey="1"></li>
<li id="li9" data-row="2" data-col="3" data-sizex="2" data-sizey="1"></li>
<li id="li10" data-row="3" data-col="3" data-sizex="2" data-sizey="1"></li>
<li id="li11" data-row="4" data-col="3" data-sizex="2" data-sizey="1"></li>


<li id="li12" data-row="1" data-col="5" data-sizex="2" data-sizey="1"></li>
<li id="li13" data-row="2" data-col="5" data-sizex="2" data-sizey="1"></li>
<li id="li14" data-row="3" data-col="5" data-sizex="2" data-sizey="1"></li>
<li id="li15" data-row="4" data-col="5" data-sizex="1" data-sizey="1"></li>
<li id="li16" data-row="4" data-col="6" data-sizex="1" data-sizey="1"></li>

<li id="li17" data-row="1" data-col="8" data-sizex="2" data-sizey="1"></li>
<li id="li18" data-row="2" data-col="8" data-sizex="2" data-sizey="1"></li>
<li id="li19" data-row="3" data-col="8" data-sizex="2" data-sizey="1"></li>
<li id="li20" data-row="4" data-col="8" data-sizex="1" data-sizey="1"></li>
<li id="li21" data-row="4" data-col="9" data-sizex="1" data-sizey="1"></li>

</ul>
</div>


Grid Elements

gridster.js

$(document).load(function () {
var grid_canvas = $(".gridster > ul").gridster( 
{ widget_margins: [3, 3],        
widget_base_dimensions: [110, 110],
       
widget_selector: "> ul"
         Define which elements are the widgets. Can be a CSS Selector string or a jQuery collection of HTML Elements.

widget_margins: [3, 3]
         Horizontal and vertical margins respectively for widgets.

widget_base_dimensions: [110, 110]
         Base widget dimensions in pixels. The first index is the width, the second is the height.


serialize_params: function($w, wgd)
{
return {
id: $($w).attr('id'),
col: wgd.col,
row: wgd.row,
size_x: wgd.size_x,
size_y: wgd.size_y,
};
},

 
 A function used to return serialized data for each each widget, used when calling the serialize method. Two    arguments are passed - $w is the jQuery wrapped HTMLElement which is used to get the id, wgd represents the grid coordinates object with keys col, row, size_x and size_y.
           
draggable: 
{
stop: function(event, ui) {
var positions = JSON.stringify(this.serialize());
localStorage.setItem('positions', positions);
$.post(
"process.php",
{"positions": positions},
function(data)
{
if(data==200)
console.log("Data successfully sent to the server");
else
console.log("Error: Data cannot be sent to the server")
}
);}
}
    }).data('gridster');

.serialize( ) creates an array of objects representing the current position of all widgets in the grid.
 Returns an Array of Objects (ready to be encoded as a JSON string) with the data specified by the serialize_params option


JSON.stringify() converts a primitive value, object or array to a JSON-formatted string that can later be parsed with JSON.parse().


localStorage.setItem('positions', positions) :
With HTML5, web pages can store data locally within the user's browser.


Note: Earlier, this was done with cookies. However, Web Storage is more secure and faster. The data is not included with every server request, but used ONLY when asked for. It is also possible to store large amounts of data, without affecting the website's performance. The data is stored in key/value pairs, and a web page can only access data stored by itself.


You can also send the serialize json array to the server using the jQuery POST method. A 'data' status of 200 implies success


draggable.stop : A callback for when dragging stops.

You can also implement other draggable options based on your requirements:
draggable.start : A callback for when dragging starts.
draggable.drag : A callback for when the mouse is moved during the dragging.



Include this gradient.js file into your index.html through the following lines :

<script type="text/javascript" src="gridster.js"></script>



Now to get the positions of the elements (remember we had stored it in the local storage),
we need to parse the items one by one by using the following lines of code:


var localData = JSON.parse(localStorage.getItem('positions'));

if(localData!=null)
{
$.each(localData, function(i,value){

    var id_name;

id_name="#";
id_name = id_name + value.id;

$(id_name).attr({"data-col":value.col, "data-row":value.row, "data-sizex":value.size_x, "data-sizey":value.size_y});

             });
}
else{
console.log('No data stored in the local storage. Continue with the default values');
}



If the local storage contains the positions, parameters for the li tag are fetched and the elements are loaded accordingly else the default grid is loaded.
You can also clear the localStorage using localStorage.clear() function.


Also instead of fetching the positions from the localStorage, if you need to fetch it from the server you can using the following code:

$.getJSON("url_here", function(data)  
{ 
if(data!=null)  
{  
$.each(data, function(i,value){       
                  var id_name;id_name="#";  
                  id_name = id_name + value.id;  
                  $(id_name).attr({"data-col":value.col, "data-row":value.row, "data-sizex":value.size_x, "data-sizey":value.size_y}); });
  }

                             else{
                                        console.log('No data returned by the server. Continue with the default positions');
                                   }
                    }  

Note: Use of local storage is not preferred for business use since a user can use the application from different machines in which case the positions cannot be retrieved. The reason behind this is it is stored in a machine's local storage and hence can only be accessed by that particular machine.

Default grid elements


Dynamic loading of grid elements

You can view the demo at:

Hope this information was useful. If you have any doubts or getting any errors just leave a comment and I will try my best to help you out.

Source: gridster.net


22 comments:

  1. Thanks, this is the only working example. :)

    ReplyDelete
  2. Thanks it helps me a lot

    ReplyDelete
  3. show, thanks. I'm brazilian, "obrigado"!

    ReplyDelete
  4. Thanks Maharshi.
    This really got me going, but i got stuck at one place,
    See,I had completely functional HTML page, in which I had 'table', 'tr' and 'tds'
    Now, once I converted, this table in ‘Gridster’, my entire jQuery click event stopped firing e.g.
    $("#imgUser").click(function () {
    alert(“you clicked on user’s photo”)
    });
    What did I do wrong?
    seems that JavaSscript function are ok.
    thanks & regards
    ...veeru

    ReplyDelete
    Replies
    1. Never mind.
      I got it fixed. it was issue of JQuery version conflict.
      thanks & regards
      ...veeru

      Delete
  5. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. Hi,
      Did you get your answer?
      I was a bit busy earlier so didn't reply

      Delete
  6. very sorry, I'm trying the demo with chrome and explorer but it doesn't work

    ReplyDelete
    Replies
    1. In case it's still not working, you can watch the demo here :
      Hope this helps.

      https://www.youtube.com/watch?v=hCRViIKZXR8&feature=youtu.be

      Delete
    2. Hello Maharshi and thanl you very much for reply.
      I've upgraded my IE and now I'm able to see the demo correctly.
      But, I have a problem, please help me, I need it...
      I've added the function that I'll paste here below, It seems to work, in fact it saves to localstorage and load from local storage and values are correct but.... when page is reloaded, tiles remain in the original position!. I'm getting crazy, can't understand what I'm doing wrong.

      $(function () { //DOM Ready


      var gridster = $(".gridster > ul").gridster(


      {
      widget_margins: [10, 10],


      widget_base_dimensions: [200, 225],

      serialize_params: function ($w, wgd) {
      return {
      id: $($w).attr('id'),
      col: wgd.col,
      row: wgd.row,
      size_x: wgd.size_x,
      size_y: wgd.size_y,
      };
      },

      draggable:

      {

      stop: function (event, ui) {
      console.log('inside stop');
      var positions = JSON.stringify(this.serialize());

      localStorage.setItem('positions', positions);

      console.log(positions);

      $.post(

      "process.php",

      { "positions": positions },

      function (data) {

      if (data == 200)

      console.log("Data successfully sent to the server");

      else

      console.log("Error: Data cannot be sent to the server")

      }

      );
      }

      }

      }).data('gridster');


      var localData = JSON.parse(localStorage.getItem('positions'));

      if (localData != null) {
      $.each(localData, function (i, value) {

      console.log('found positions');
      console.log(value.col);
      console.log(value.row);
      console.log(value.size_x);
      console.log(value.size_y);
      var id_name;

      id_name = "#";
      id_name = id_name + value.id;

      $(id_name).attr({ "data-col": value.col, "data-row": value.row, "data-sizex": value.size_x, "data-sizey": value.size_y });

      });
      }
      else {

      console.log('No data stored in the local storage. Continue with the default values');
      }

      });

      Delete
  7. wow wow wow, amazing tutorial, im looking for this...
    thanks bro

    ReplyDelete
  8. Any tips on how to make this responsive?

    ReplyDelete
  9. Didn't try that before. Try adding bootstrap styles for responsive behavior, or you might have to write your own custom styles to make it responsive.
    Good thought though. Will definitely increase the usability of the plugin

    ReplyDelete
    Replies
    1. Thank you, the problem with adding bootstrap styles is that it seems the stylesheet that you are building via javascript is countering all other grid styles. Even with !important updates to the grid are not working for me. Any ideas around that? I appreciate the response.

      Delete
  10. Anybody tried to export Gridster content to PDF especially when gridster content is large in terms of height.
    Any suggestions would be appreciated.

    ReplyDelete
    Replies
    1. By exporting, do you mean exporting the grid positions as a pdf file which later can be downloaded from the UI or did you mean something else?

      Delete
  11. If i need responsive , how to manage for support responsive I use gridster.js - v0.5.6 - 2014-09-25

    ReplyDelete
  12. I was wondering if there was any way save the positions as well as classes of widgets that have been dynamically added to the grid?

    ReplyDelete
  13. Briliant bro, just like windows 8 :D

    ReplyDelete
  14. Can you please explain why serialize is using here? Where it affects the demo?

    ReplyDelete
  15. Is there any solution, to set dynamic content in harizantal

    ReplyDelete