title: How to set widget data from local storage using gridstack.js
body: <h3>Scenario</h3>
  
  <p>I have a dashboard with some widgets grouped into tabs that the user can click through. The widgets have default starting positions including height and width, but if the user moves or resizes them (using <code>gridstack.js</code>) I save the new widget data to local storage.</p>
  
  <p>If the user clicks between tabs the new widget positions are maintained.</p>
  
  <h3>Problem</h3>
  
  <p>When the user refreshes the page, the default widget positions are loaded instead of the data in local storage. I tried to set the new positions using <code>getWidgetData()</code> but no luck.</p>
  
  <p>I have checked local storage for my <code>grid-layout</code> data and the new positions are present.</p>
  
  <h3>Code example</h3>
  
  <p>Here is <a href="https://codepen.io/ahdigital/pen/NzwVBV" rel="nofollow noreferrer">Codepen</a> since I think SO  requires <code>allow-same-origin</code>, thus breaking the snippet.</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>// Initialize zurb foundation
  $(document).foundation();
  
  $(function() {
    var grid = $('.grid-stack').data('gridstack');
  
    var options = {
      cellHeight: 40,
      verticalMargin: 28,
      animate: false,
    };
  
    // Initialize grid-stack widgets
    widgetsInit = function(options) {
      $('.grid-stack').gridstack(options);
      getWidgetData(); // Find and set positions from local storage
    }
  
    updateVisibleWidgetHeights = function(options) {
      var targetPanel = '.tabs-panel.is-active';
  
      $(targetPanel + ' .grid-stack .grid-stack-item').each(function(i){
        $(targetPanel + ' .grid-stack').data('gridstack').resize(
          $(targetPanel + ' .grid-stack .grid-stack-item')[i],
          $($(targetPanel + ' .grid-stack .grid-stack-item')[i]).attr('data-gs-width'),
          Math.ceil(($(targetPanel + ' .grid-stack .grid-stack-item .grid-stack-item-content')[i].scrollHeight + $(targetPanel + ' .grid-stack').data('gridstack').opts.verticalMargin) / ($(targetPanel + ' .grid-stack').data('gridstack').cellHeight() + $(targetPanel + ' .grid-stack').data('gridstack').opts.verticalMargin))
        );
      });
    }
  
    updateAllWidgetHeights = function(options) {
      $('.grid-stack .grid-stack-item').each(function(i){
        $('.grid-stack').data('gridstack').resize(
          $('.grid-stack .grid-stack-item')[i],
          $($('.grid-stack .grid-stack-item')[i]).attr('data-gs-width'),
          Math.ceil(($('.grid-stack .grid-stack-item .grid-stack-item-content')[i].scrollHeight + $('.grid-stack').data('gridstack').opts.verticalMargin) / ($('.grid-stack').data('gridstack').cellHeight() + $('.grid-stack').data('gridstack').opts.verticalMargin))
        );
      });
    }
  
    getWidgetData = function() {
      // // Load from local storage
      var serialization = null;
      if (serialization = localStorage.getItem("grid-layout")) {
        _.each(JSON.parse(serialization), function (node) {
          // Update each widget's properties from values in storage
          $('.grid-stack-item[data-custom-id='+ node.id +']').attr({
            'data-gs-x': node.x,
            'data-gs-y': node.y,
            'data-gs-width': node.width,
            'data-gs-height': node.height,
          });
        });
      } else {
        console.log("There was no local storage data to read")
      }
    }
  
    widgetsInit(options);
    updateVisibleWidgetHeights();
  
    $('.grid-stack').on('change', function (event, items) {
      // Save data to local storage
      var res = _.map($('.grid-stack .grid-stack-item'), function (el) {
        el = $(el);
        node = el.data('_gridstack_node');
        return {
          // Grab widget properties
          id: el.attr('data-custom-id'),
          x: node.x,
          y: node.y,
          width: node.width,
          height: node.height
        };
      });
      localStorage.setItem("grid-layout", JSON.stringify(res))
    });
  
    // On tab change update widget heights to the height of the content they contain
    $(document).on('change.zf.tabs', function() {
      updateVisibleWidgetHeights();
    })
  });</code></pre>
  <pre class="snippet-code-css lang-css prettyprint-override"><code>.grid-stack &gt; .grid-stack-item &gt; .grid-stack-item-content {
      background-color: #fff;
      cursor: move;
      border: 1px solid #e3e3e3;
      border-radius: 4px;
   padding: 1rem;
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;link href="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/0.4.0/gridstack.min.css" rel="stylesheet"/&gt;
  &lt;link href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.4.3/css/foundation.min.css" rel="stylesheet"/&gt;
  &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"&gt;&lt;/script&gt;
  &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"&gt;&lt;/script&gt;
  &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"&gt;&lt;/script&gt;
  &lt;script src='https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/0.4.0/gridstack.min.js'&gt;&lt;/script&gt;
  &lt;script src='https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/0.4.0/gridstack.jQueryUI.min.js'&gt;&lt;/script&gt;
  &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.4.3/js/foundation.min.js"&gt;&lt;/script&gt;
  
  
  &lt;ul class="tabs" data-tabs id="example-tabs" data-deep-link="true" data-update-history="true" data-match-height="false"&gt;
    &lt;li class="tabs-title is-active"&gt;&lt;a href="#panel1" aria-selected="true"&gt;Tab 1&lt;/a&gt;&lt;/li&gt;
    &lt;li class="tabs-title"&gt;&lt;a href="#panel2"&gt;Tab 2&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
  
  &lt;div class="tabs-content unstyled" data-tabs-content="example-tabs"&gt;
    &lt;div class="tabs-panel is-active" id="panel1"&gt;
      &lt;div class="grid-stack"&gt;
        &lt;div class="grid-stack-item" data-gs-x="0" data-gs-y="0" data-gs-width="4" data-gs-height="2"&gt;
          &lt;div class="grid-stack-item-content"&gt;#1&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="grid-stack-item" data-gs-x="4" data-gs-y="0" data-gs-width="4" data-gs-height="2"&gt;
          &lt;div class="grid-stack-item-content"&gt;#2&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="grid-stack-item" data-gs-x="8" data-gs-y="0"data-gs-width="4" data-gs-height="2"&gt;
          &lt;div class="grid-stack-item-content"&gt;#3&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="tabs-panel" id="panel2"&gt;
      &lt;div class="grid-stack"&gt;
        &lt;div class="grid-stack-item" data-gs-x="0" data-gs-y="0" data-gs-width="4" data-gs-height="2"&gt;
          &lt;div class="grid-stack-item-content"&gt;#4&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="grid-stack-item" data-gs-x="4" data-gs-y="0" data-gs-width="4" data-gs-height="2"&gt;
          &lt;div class="grid-stack-item-content"&gt;#5&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="grid-stack-item" data-gs-x="8" data-gs-y="0" data-gs-width="4" data-gs-height="2"&gt;
          &lt;div class="grid-stack-item-content"&gt;#6&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;</code></pre>
  </div>
  </div>
  </p>