Saving state with the jQuery Accordion Menu
I have been working on the new True Negative website pretty much non-stop lately and I’m using several differernt things from the jQuery JavaScript library. One of these is the jQuery Accordion Menu, from their User Interface library. It’s a great simple menu that can be implemented with very little javascript code.
One thing that it doesn’t inherently support is saving the state between webpages, which is something I had wanted since I’m using it as a menu, not just for content display. Functionally, I knew what had to be done in order to get it to save state. It was obvious that I needed to use cookies and some quick javascript to save what menu was open. I then came across the jQuery Cookie plugin, which really simplifies working with cookies in jQuery.
Setting a cookie with the plugin is as simple as follows:
$.cookie('cookiename', 'cookiecontents');
The accordion menu has an event change attribute, which can be set to a function or just inline code. Using both this feature and the cookie plugin, it was very simple to write the code that I needed in order to get the result I wanted. Here is the code and I will explain it below:
// accordion menu $('#menu').accordion({ header: 'h3', navigation: true, active: '.selected', autoHeight: false, clearStyle: true, collapsible: true, alwaysOpen: false, animated: 'slide', change: function(event,ui) { var hid = ui.newHeader.children('a').attr('id'); if (hid === undefined) { $.cookie('menustate', null); } else { $.cookie('menustate', hid, { expires: 2 }); } } }); // check cookie for accordion state if($.cookie('menustate')) { $('#menu').accordion('option', 'animated', false); $('#menu').accordion('activate', $('#' + $.cookie('menustate')).parent('h3')); $('#menu').accordion('option', 'animated', 'slide'); }
The first section is pretty straightforward. It defines and applies the accordion menu to a div tag with an id of menu. All of the various options are laid out in the Accordion docs and I just set some of the standard ones in order to get the look and feel that I wanted. The important part is the change option:
change: function(event,ui) { var hid = ui.newHeader.children('a').attr('id'); if (hid === undefined) { $.cookie('menustate', null); } else { $.cookie('menustate', hid, { expires: 2 }); }
Here you can see that I check the value of the menu that is open to see if it is undefined, which would mean the menu is closed. If it is open, it will have a value in there, so I store that in a cookie called “menustate” for use when the page is reloaded.
// check cookie for accordion state if($.cookie('menustate')) { Â Â Â Â Â Â Â Â $('#menu').accordion('option', 'animated', false); Â Â Â Â Â Â Â Â $('#menu').accordion('activate', $('#' + $.cookie('menustate')).parent('h3')); Â Â Â Â Â Â Â Â $('#menu').accordion('option', 'animated', 'slide');
Upon page reload I have it check the “menustate” cookie to see if it has been set or not. If it is, I first turn off the animation so the visitor does not see it open again, then I call the activate method to open the one with the id that is stored in the cookie. Lastly, I reenable the animation. It works great!
Unfortunately, I have no completed the True Negative site yet, so I do not have an example of this working. As soon as I finish the site, I’ll update this blog post with a link to it. Hope this helps anyone trying to do this in a simple way. Thanks for reading!
cheers for this, saved my bacon
you just need path: ‘/’ in the part that writes, or you end up with multiple cookies
$.cookie(‘menustate’, hid, { path: ‘/’, expires: 2 });
Thanks for the correction! 🙂
Many thanks for sharing.
The variable ‘hid’ never did get a value in my setup (Ubuntu 9.04 Firefox 3.013, jQuery 1.3.2, ui 1.7.2). I have tried different things. this works for me:
jQuery(document).ready(function(){
var drawer = jQuery.cookie(‘accdrawer’);
if(drawer === undefined) {
drawer = “0”;
}
jQuery(‘#accordion’).accordion({
header: ‘h3’,
navigation: false,
active: parseInt(drawer),
autoHeight: false,
clearStyle: true,
collapsibe: true,
alwaysOpen: true,
animated: ‘slide’,
change: function(event,ui) {
var index = jQuery(this).find(“h3”).index(ui.newHeader[0]);
if (index > -1) {
jQuery.cookie(“accdrawer”, index, {path: “/”});
}
}
}
);
});
Example of this working would be really nice, since I just can’t make it work 🙁
I know I know! It’s coming soon. I swear! 🙂
Thanks Per Jensen,
I didn’t get the cookie thing to work but your solution works like a charm
Per Jensesn,
Thanks for your suggstion. It seems to e working for un-nested accordions, but for nested I’m having trouble as is collapses all as soon as I click on the sub-accordion. Here’s my code:
jQuery(document).ready(function(){
var drawer = jQuery.cookie(‘accdrawer’);
if(drawer == undefined) {
drawer = “0”;
}
jQuery(‘#accordion2’).accordion({
header: ‘h3’,
navigation: false,
active: parseInt(drawer),
autoHeight: false,
clearStyle: true,
collapsible: true,
alwaysOpen: true,
animated: ‘slide’,
change: function(event,ui) {
var index = jQuery(this).find(“h3”).index(ui.newHeader[0]);
if (index > -1) {
jQuery.cookie(“accdrawer”, index, {path: “/”});
}
}
});
});
Main
Search
Test
Review
Database
Summary
Dashboard
Summary
Hi Mike,
Thanks for the code.
Any news on when you might have a working example?
Working example is up (unofficially) at http://www.truenegative.com
Take a look and let me know what you think!
Thanks for article.
How to store nested list accordions ?
In you example http://www.truenegative.com you have 1 level accordion with
Here it is nested list accordion – http://blog.evaria.com/wp-content/themes/blogvaria/jquery/index-multi.php
Any ideas?
Thank you for answer 🙂
Setting the navigation attribute to true will let the accordion automatically handle this for you.
From jQuery Documentation:
navigation
Type:Boolean
Default:false
If set, looks for the anchor that matches location.href and activates it. Great for href-based state-saving. Use navigationFilter to implement your own matcher.
Right, that will work for having the anchor tag in the address bar. Using a cookie circumvents that. I can’t remember why I didn’t want it in the address bar, but it will come to me haha.
Your site was extremely interesting, especially since I was searching for thoughts on this subject last Thursday.
I’m Out! 🙂
thanks for sharing, just a little bug, pay attention, in the code is written “collapsibe” instead of “collapsible”.
Thanks, your article saved my day! And another big thanks to HelpSeeker, as it was his posted changes which made it all work.
@maumau Thanks! Fixed the typo 🙂
Hi,
thanks for the cue.
I´ve found one bug – when I implemented thi code to my site, it was working fine, but sometimes, the active field collapsed back to “inactive” state. So I was trying to fix it and there is the solution. If you are experiencing the same, set the parameter “Navigation” to false value.
Very useful and thanks very much for sharing.
Any idea on how to have this work per page? If I copy this page into a new page, jq and all, it reads the cookie. If a site uses multiple accordions this is not how it should work.
How can I make this accordion move more smoothly?
It’s ok when it’s opening but when closing a panel it’s not smooth at all.
Nothing I found here worked for my particular installation. I developed my own way using the index, if anyone finds this useful:
$(document).ready(function() {
$(‘#accordion’).accordion({
autoHeight: false,
collapsible: true,
active: false,
change: function(event,ui) {
var index = ui.options.active;
if (index > -1) {
$.cookie(‘accidx’, index, {expires: 2, path: ‘/’});
}
}
});
if ($.cookie(‘accidx’) > -1) {
var idx = Number($.cookie(‘accidx’));
$(‘#accordion’).accordion(‘option’, ‘animated’, false);
$(‘#accordion’).accordion(‘activate’,idx);
$(‘#accordion’).accordion(‘option’, ‘animated’, ‘slide’);
}
});
Here’s a working example (except for the cookie getter/setter)
jQuery(document).ready(function() {
var selected = readCookie(‘activeMkt’);
var select = -1;
if (selected){
select = parseInt(selected);
}
$( “#accordion” ).accordion({
header: ‘h3’,
autoHeight: false,
navigation: true,
collapsible: true,
alwaysOpen: false,
animated: ‘slide’,
active: select,
change: function(event,ui) {
var sel = ui.newHeader.children(‘a’).attr(‘id’);
if (sel === undefined) {
setCookie(‘activeMkt’,’-1′);
} else {
setCookie(‘activeMkt’,sel);
}
}
});
});
EINS
EIN
ZWEI
ZWE
DREI
DRE
thanks for your sharing,I use accordion menu on my website…
I am very much new to Jquery. what I want is something very simple. Could anyone please tell me how to achieve this.
I have two menu’s which needs to be ‘remembered’ by the browser.
1. A menu that is hidden initially and shown when clicked on a link
2. I have put ‘help-hints’ allover the site. There is a button to hide the hint icons.
What I want is : Once that main menu is shown, it should stay shown while browsing through the pages. Same with the hint icons. When someone clicks on the link that hides/shows the hint icons, they should get hidden/displayed.
The following is my code :
JQuery :
jQuery(‘.slideout’).click(function() {
jQuery(‘.sf-green’).slideToggle();
jQuery(‘.slideout, .slidein’).toggleClass(‘slidein slideout’);
});
jQuery(‘#infobutton’).click(function(){
jQuery(‘.info_on, .info_off’).toggleClass(‘info_off info_on’);
jQuery(‘.hint, .hintoff’).toggleClass(‘hintoff hint’);
});
HTML
Main Menu
Help »
Any help will be great!
Thank you!
Thank you so much! you saved my day on implementing this in my website haha love you~
Useful and brilliant thank you for sharing this. save me today this did.
Just used it today with some edits.
cookie plugin can be found here: https://github.com/carhartl/jquery-cookie
I’ve put it on jsbin for easy cut’n’pasting
It only works in edit mode though,
http://jsbin.com/ekuhap/1/edit
thanks!
Thanks everyone for sharing, I combined a few of these ideas, which let me understand what was is going on.
Simplest solution:
$(function () {
var myact = false;
$( “#myaccordion” ).accordion({
clearStyle: true,
collapsible: true, // allow to close completely
create: function (event, ui) {
//get index in cookie on accordion create event
if (($.cookie(‘saved_index’) != null) && ($.cookie(‘saved_index’) != ‘false’)) {
myact = parseInt($.cookie(‘saved_index’));
}
},
change: function (event, ui) {
//set cookie for current index on change event
myact = ui.options.active;
$.cookie(‘saved_index’, null, { expires: 2, path: ‘/’ }); // session cookie
$.cookie(‘saved_index’, myact, { expires: 2, path: ‘/’ });
},
active: ($.cookie(‘saved_index’) == null) ? 0 : ($.cookie(‘saved_index’) == ‘false’) ? false : parseInt($.cookie(‘saved_index’))
});
});
thanks for your help.if i want do it by myself i have to spend two hour except 5 minutes.
with the best wishes.
for more informatoion about accordian menu visit this blog
lessonsone.blogspot.in and get live demo with free download.
Hi, this is soo nice feature but I just dont get it to modify my jquery ui accordion 🙁
Do I need the jquery.cookie.js plugin?
this is my code:
$(“.accordion”).accordion({
canToggle: true,
canOpenMultiple: true,
change: function(event,ui) {
var hid = ui.newHeader.children(‘a’).attr(‘id’);
if (hid === undefined) {
$.cookie(‘menustate’, null);
} else {
$.cookie(‘menustate’, hid, { path: ‘/’, expires: 2 });
}
}
});
// check cookie for accordion state
if($.cookie(‘menustate’)) {
$(‘#menu’).accordion(‘option’, ‘animated’, false);
$(‘#menu’).accordion(‘activate’, $(‘#’ + $.cookie(‘menustate’)).parent(‘h3’));
$(‘#menu’).accordion(‘option’, ‘animated’, ‘slide’);
}
THANKS in advance for your help.
regards from germany