2

A bit of a js/jquery novice - I'm using Bootstrap and data-toggle + collapse classes to show/hide divs. I've been scouring the 'net trying to find something that will maintain the state of all divs, whether identified by a unique ID or a CLASS, between page refreshes. I've seen discussions on cookies and local storage, I don't think I care which method is used (although I've had errors with $.cookie is not a function, so maybe local storage is better?).

The issue is most examples deal with maintaining accordion states, which I don't think exactly apply here. I've tried modifying various code examples but they just don't quite seem to work.

Here is an example of my code:

<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" />
<div class="panel panel-danger">
  <div data-toggle="collapse" href="#duesoon" style="cursor: pointer;" class="panel-heading">
    <font class="panel-title"><span class='glyphicon glyphicon-fire'></span> Top 5 Expiring Tasks</font>
  </div>
  <div id="duesoon" class="collapse">
    <table class="table table-hover table-striped table-condensed">
      <thead>
        <tr>
          <th class='col-md-7'>Name</th>
          <th class='col-md-5'>End Date</th>
        </tr>
      </thead>
      <tbody>
        <tr style="cursor: pointer;" onclick="document.location = '?action=view&type=project&id=2">
          <td><span class='glyphicon glyphicon-triangle-right'></span> Take Out The Trash</td>
          <td>Yesterday</td>
        </tr>
      </tbody>
    </table>
  </div>
  <div data-toggle="collapse" href="#urgency" style="cursor: pointer;" class="panel-heading">
    <font class="panel-title"><span class='glyphicon glyphicon-fire'></span> Top 5 Urgent Tasks</font>
  </div>
  <div id="urgency" class="collapse">
    <table class="table table-hover table-striped table-condensed">
      <thead>
        <tr>
          <th class='col-md-7'>Name</th>
          <th class='col-md-5'>Priority</th>
        </tr>
      </thead>
      <tbody>
        <tr style="cursor: pointer;" onclick="document.location = '?action=view&type=project&id=1">
          <td><span class='glyphicon glyphicon-triangle-right'></span> Save the Whales</td>
          <td>Critical</td>
        </tr>
      </tbody>
    </table>
  </div>
</div>

As you can see, there's a link or a button or something that toggles showing/hiding a div.

Same thing on JSFiddle: http://jsfiddle.net/w8psgvaa/2/

I found this code example;

 $('.collapse').on('hidden', function() {
       // store this.id
 }).on('shown', function() {
       // delete this.id
 });

 $(document).ready(function(){
     $(".collapse").collapse().each(function(){
         if( isStored( this.id ) ) {
             $( this ).collapse( 'hide' );
         }
     });
 });​

But unfortunately it's incomplete. and some divs start out collapsed (as in my example). Any help is appreciated!

  • you get the cookie error because you are not including the js library for it --- https://github.com/carhartl/jquery-cookie or https://github.com/js-cookie/js-cookie – Tasos May 23 '15 at 18:37
  • Hi Tasos, yes it is not included in the sample above, but I have included it when trying some of the cookie code examples and I was still getting that error. Perhaps it's a conflict with something else or an issue with the code I was using. Thanks! – Vasilios Betoglou May 23 '15 at 18:46
  • Thanks humble, I'll look more into this and see if I can apply it to what I'm trying to accomplish. I'm more of a back-end guy (PHP) - but I need to learn more about front-end coding. – Vasilios Betoglou May 23 '15 at 18:47

2 Answers2

3

You are looking in the right direction. My solution would be the following.

Use LocalStorage, available in modern browsers.

  • When a div is collapsed: remove the div's ID from the storage
  • When a div is opened: add the div's ID from the storage.

This is as easy as

var shown = []

// On collapse
shown.remove($(this).attr('id'));
localStorage.setItem('shown', shown);

// On open
shown.push($(this).attr('id'));
localStorage.setItem('shown', shown);

// On page load
var shown = localStorage.getItem('shown');
for (var s in shown) {
    $('#' + s).show(); // Or whatever API you use to un-collapse the div
}

More information: http://diveintohtml5.info/storage.html

Hidde
  • 11,493
  • 8
  • 43
  • 68
  • Hi Hidde, thanks for the info. I guess where I'm having trouble is putting it all together with my example above. What I'm trying to accomplish, and I don't even know if this is possible, is for when the page loads, the div is either seen or hidden (collapse is hidden, collapse in is shown, using bootstrap, so I'm guessing show.bs()?), either by its default class state if it has not been expanded or collapsed, or by its last state if it has been (expanded or collapsed). – Vasilios Betoglou May 24 '15 at 11:53
  • OK, you are using Bootstrap. My advice is first trying to use the localstorage, test the methods you need, and then start thinking about using localStorage to keep track of the state of the collapsing divs through different page loads. – Hidde May 24 '15 at 14:52
  • Hi Hidde, as I had mentioned, I'm a pretty big novice when it comes to JS/JQuery. I've done enough programming to have "A-HA" moments when I see working examples, but unfortunately I don't know enough to connect the dots with what you're saying. Thanks for the information though - at least I know what it is I need to learn next. – Vasilios Betoglou May 26 '15 at 00:35
  • If the general knowlegde of JavaScript/jQuery is the problem I suggest you learn that first, before you start with specific problems. I wouldn't know how to explain it in more detail without writing all your code for you. – Hidde May 26 '15 at 09:52
  • Hii there, sorry for bothering you after a year, but I've came across this answer when working on my own project, unfortunately, I can't seem to get it to work. When I use it, I get this: `Uncaught TypeError: shown.remove is not a function` is there something I'm missing? – Finlay Roelofs Nov 04 '16 at 18:25
  • Did you define `shown` correctly (as an array), in the correct scope? – Hidde Nov 07 '16 at 10:04
  • I'm a JS newbie as well, but I think an array structure cannot be preserved in localStorage without additional steps described here: https://stackoverflow.com/questions/2010892/storing-objects-in-html5-localstorage – VPfB Jan 16 '18 at 16:17
1

Here is a working example, using Bootstrap panel-collapse and LocalStorage, similar to Hidde's answer. I'm using JSON "stringify" and "parse" functions to store my ids in localStorage, which stores everything as strings. I also use Bootstrap's collapse events.

// On document ready

var shownOnRefresh = [];
localStorage.setItem('shownOnRefresh', JSON.stringify(shownOnRefresh));

$('#myParentElement').on('shown.bs.collapse', '.panel-collapse', function() {
        shownOnRefresh = JSON.parse(localStorage.getItem('shownOnRefresh'));
        if ($.inArray($(this).attr('id'), shownOnRefresh) == -1) {
            shownOnRefresh.push($(this).attr('id'));
        };
        localStorage.setItem('shownOnRefresh', JSON.stringify(shownOnRefresh));
});

$('#myParentElement').on('hidden.bs.collapse', '.panel-collapse', function() {
        shownOnRefresh = JSON.parse(localStorage.getItem('shownOnRefresh'));
        shownOnRefresh.splice( $.inArray($(this).attr('id'), shownOnRefresh), 1 );//remove item from array
        localStorage.setItem('shownOnRefresh', JSON.stringify(shownOnRefresh));
});

// On page refresh
var shownOnRefresh = JSON.parse(localStorage.getItem('shownOnRefresh'));
for (var i in shownOnRefresh ) {
    $('#' + shownOnRefresh [i]).addClass('in');
}

I'm a jquery novice, so this code can certainly be optimized, but it does the job.

Roubi
  • 1,989
  • 1
  • 27
  • 36