ratherBeKiting
ratherBeKiting

Reputation: 275

Bootstrap Accordion. Retain state on pageload for multiple panels

I am using bootstrap accordion on form page. The user can open multiple panels at the same time. After the form is submitted, I would like to retain the state of any of the Bootstrap accordion panels that were open.

I have modified some code I found on stack overflow to do this using local storage, as below:

Accordion HTML
-------------------

<div class="panel-group" id="accordion">

  <div class="panel panel-default">
    <div class="panel-heading">
      <div class="panel-title"> <a data-toggle="collapse" href="#client_12325">Panel heading</a> </div>
    </div>
    <div id="client_12325" class="panel-collapse collapse">
      <div class="panel-body">Panel Content</div>
    </div>
  </div>

  <div class="panel panel-default">
    <div class="panel-heading">
      <div class="panel-title"> <a data-toggle="collapse" href="#client_12326">Panel heading</a> </div>
    </div>
    <div id="client_12326" class="panel-collapse collapse">
      <div class="panel-body">Panel Content</div>
    </div>
  </div>

 <div class="panel panel-default">
    <div class="panel-heading">
      <div class="panel-title"> <a data-toggle="collapse" href="#client_12327">Panel heading</a> </div>
    </div>
    <div id="client_12327" class="panel-collapse collapse">
      <div class="panel-body">Panel Content</div>
    </div>
  </div>

</div>

Javascript
---------------

<script>
$(document).ready(function() {

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

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

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

});


var retainStateArray = JSON.parse(localStorage.getItem('retainState'));
var arrayLength = retainStateArray.length;
for (var i = 0; i < arrayLength; i++) {
    var panel = '#'+retainStateArray[i];
    $(panel).addClass('in');
    console.log(panel);
}
</script>

There are 2 issues with this code

1/ It gets the correct ID's of the panels on page refresh (you can see via the console log within the loop), however it fails to add the class 'in' to the panels.

2/ It only retains the state for the first page reload. I would like it to retain the state for the entire user session no matter how many times the page is reloaded.

Thanks in advance.

Upvotes: 0

Views: 1957

Answers (3)

ratherBeKiting
ratherBeKiting

Reputation: 275

Managed to get this working. I am certain this code could be much more pretty

$(document).ready(function() {

  var lastState = localStorage.getItem('lastState');

  if (!lastState) {
    lastState = [];
    localStorage.setItem('lastState', JSON.stringify(lastState));
  } else {
    lastStateArray = JSON.parse(lastState);
    var arrayLength = lastStateArray.length;
    for (var i = 0; i < arrayLength; i++) {
        var panel = '#'+lastStateArray[i];
        $(panel).addClass('in');
    }
  }

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

  $('#accordion').on('hidden.bs.collapse', '.panel-collapse', function() {
    lastState = JSON.parse(localStorage.getItem('lastState'));
    lastState.splice( $.inArray($(this).attr('id'), lastState), 1 ); 
    localStorage.setItem('lastState', JSON.stringify(lastState));
  });

});

Upvotes: 1

Matthew Tilley
Matthew Tilley

Reputation: 149

Why not use js-cookies if you're not opposed to adding an extra js library.

When the submit button is clicked, create a cookie with the ID's that have the 'in' class selected.

If the cookie does not exist
Default accordion state is observed.

If the cookie does exist
Test if "#accordion" exists on current page
Fetch the ID's from the cookie
Parse the dom for the ID's
Apply the class 'in'

Win?

Upvotes: 2

Christian Esperar
Christian Esperar

Reputation: 528

On your code, when the DOM is ready it will always set the localstorage to empty array since you assign empty array to retainState.

What you can do is check first if localstorage is exist then assign it to retainState.

Upvotes: 1

Related Questions