I have an accordion style navigation list set up so that when categories are clicked it opens up to show sub-categories that link to pages.
What I would like to do is have the accordion navigation list keep it's open or closed state when the new page opens.
I've gathered that cookies work to retain the state on refresh, but how do I retain the state when a different page is visited? All the pages have the same accordion navigation list.
Try Web Storage. Store the state of the tabs on page unload, restore the state on the page load event.
I found a solution, it uses the accordian plug-in found here, http://www.i-marco.nl/weblog/archive/2010/02/27/yup_yet_another_jquery_accordi and the jquery cookie.js plug-in
I added id's to the header anchor tages in the HTNL mark-up like so,
<li>
<a id="m1" class="label" href="#">Sound/Audio Systems</a>
<ul class="acitem">
<li>PA Systems</li>
<li>Loudspeakers</li>
<li>Microphones </li>
<li>DJ Equipment</li>
<li>Sound Processing Equipment</li>
</ul>
</li>
And modified the accordian.js code, I added the lines beginning with $.cookie, and the If statement in the document.ready funciton.
jQuery.fn.initMenu = function() {
return this.each(function(){
var theMenu = $(this).get(0);
$('.acitem', this).hide();
$('li.expand > .acitem', this).show();
$('li.expand > .acitem', this).prev().addClass('active'),
currentID = "";
$('li a', this).click(
function(e) {
e.stopImmediatePropagation();
var theElement = $(this).next();
var parent = this.parentNode.parentNode;
if($(parent).hasClass('noaccordion')) {
if(theElement[0] === undefined) {
window.location.href = this.href;
}
$(theElement).slideToggle('normal', function() {
if ($(this).is(':visible')) {
$(this).prev().addClass('active');
currentID = $(this).prev().attr('id');
$.cookie('menustate', currentID, {expires: 2, path: '/'});
}
else {
$(this).prev().removeClass('active');
$.cookie('menustate', null, {expires: 2, path: '/'});
}
});
return false;
}
else {
if(theElement.hasClass('acitem') && theElement.is(':visible')) {
if($(parent).hasClass('collapsible')) {
$('.acitem:visible', parent).first().slideUp('normal',
function() {
$(this).prev().removeClass('active');
$.cookie('menustate', null, {expires: 2, path: '/'});
}
);
return false;
}
return false;
}
if(theElement.hasClass('acitem') && !theElement.is(':visible')) {
$('.acitem:visible', parent).first().slideUp('normal', function() {
$(this).prev().removeClass('active');
$.cookie('menustate', null, {expires: 2, path: '/'});
});
theElement.slideDown('normal', function() {
$(this).prev().addClass('active');
currentID = $(this).prev().attr('id');
$.cookie('menustate', currentID, {expires: 2, path: '/'});
});
return false;
}
}
}
);
});
};
$(document).ready(function() {
$('.menu').initMenu();$('#side-navigation_frame').show();
if ($.cookie('menustate')) {
var anchor = "",
elementID = $.cookie('menustate');
anchor = document.getElementById(elementID);
$(anchor).addClass('active');
$(anchor).next().show();
}
});
It works nicely, not bad for a beginner, thanks for all the advise.
Rob Fenwick
Cookies "retain state" across the full path and domain for which they are specified. So if you can get them to work for just one page, you should have them work automatically on all pages of your site.
You can still use cookies, you just have to make sure they're not specific to the one page. For example:
document.cookie = 'openitem=5; expires=somedate; path=/';
will be accessible to all pages on the site. More about cookies.
Ok so I took a look at the library you are using, it's a decent library and all but you might find it easier to find solutions to your problems if you use a more standard library like jQuery UI, it has an accordion control http://jqueryui.com/demos/accordion/ and like I mentioned there are so many people using it that the answer to most problems can be found.
But like I mentioned I did take a look at your library. As others have mentioned you would use a cookie to store the value. This library supports 'pre expanding' a particular section of the accordian, to do that you would add the expand class to the element. You can either do that server side or you can do it using JavaScript before initMenu() is called.
The other less elegant option is to trigger the click event on the anchor tag after the call to initMenu. Finally you can use jQuery's show() to show expand the section without animation.
The first thing you have to do is find out which section was clicked on, then you would store that sections name in a cookie. On page load you would get that value and expand the appropriate according section. This is what the code should kinda look like - note this is psuedo code and you have fill in the appropriate parts.
$(function() {
$(".menu.collapsible .label").click(function() {
var accordianSection = $(this).text();
rememberSection(accordianSection);
});
var section = recallSection();
if(section !== undefined) {
expandSection(section);
}
});
The expandSection function can look something like this:
var sectionLink = $(".menu.collapsible .label").filter(function() {
return $(this).text() == section;
});
sectionLink.trigger('click');
Related
I am loading PHP files with JQuery/Ajax.
This is the index.php file where the webpages are called
<div class = "view-screen">
<?php include('home.php'); ?>
</div>
Depending on which nav link is clicked, that page will display without refreshing.
$(document).ready(function() {
// ...
$navLinks.click( function() {
var $this = $(this)
target = $this.data('target')
toggleMenu()
$viewScreen.load(target + ".php")
$this.data('clicked', true)
if ($this.data('clicked') && target === "about") {
activateAbout()
}
return false
})
function activateAbout() {
console.log('activated')
}
}
The console log works, and displays 'activated'. The pages do load.
All of my scripts compile and link correctly to each other.
However, when I include code that updates the target page CSS in the activateAbout() function, it doesn't work. For example:
$('body').css("background-color", "white")
in activateAbout() works, but calling/updating CSS elements in the chosen .php file doesn't, such as
$('.about p').css("color", "white")
// OR
$('.about').toggleClass('activate')
I have a feeling this has something to do with the order in which these files are loaded, but I'm not sure! Thanks for the help in advance
This is common phenomenon. The reason you are not able to apply the css is because, your content is loading after, you call activateAbout(). I would recommend to call activateAbout() once the $viewScreen.load(target + ".php") loads the data successfully. jQuery.load() supports callback too. Refer to the example usage at https://www.w3schools.com/jquery/jquery_ajax_load.asp. So, it should look like
$(document).ready(function() {
$navLinks.click( function(){
var $this = $(this);
target = $this.data('target');
toggleMenu();
$viewScreen.load(target + ".php", function() {
$this.data('clicked', true);
if ($this.data('clicked') && target === "about") {
activateAbout();
}
});
return false;
});
});
function activateAbout() {
console.log('activated')
}
Also there is a trick using setTimeout which you can execute after certain time, when the view is expected to be loaded like below
if ($this.data('clicked') && target === "about") {
//The timeout period you can change accordingly
setTimeout(activateAbout, 300);
}
The recommended way is first type solution. Hope this helps you!!
I’m working on a left menu bar that expands on a button click.
I want to save the state of the menu, if it is expanded or not.
When it refreshes the class must still be added.
$('#menu-action').click(function() {
$('.sidebar').toggleClass('active');
$('.main').toggleClass('active');
$(this).toggleClass('active');
if ($('.sidebar').hasClass('active')) {
$(this).find('i').addClass('fa-close');
$(this).find('i').removeClass('fa-bars');
} else {
$(this).find('i').addClass('fa-bars');
$(this).find('i').removeClass('fa-close');
}
});
// Add hover feedback on menu
$('#menu-action').hover(function() {
$('.sidebar').toggleClass('hovered');
});
Try Local Storage:
$(document).ready(function() {
if(localStorage.getItem("active")) {
$('.sidebar').addClass("active")
}
});
$(window).unload(function() {
localStorage.setItem("active", $('.sidebar').hasClass("active"));
});
Local storage is not supported by all browsers. See the link above. You can use extensions like store.js to support old browsers.
Another option is to use cookie plugin as mentioned here.
Since you have not yet made it clear on how you want to read or write cookies, I'd recommend using js-cookie to make handling a little easier. Handling cookies with plain JS is possible, but a rather cumbersome task.
A solution using the mentioned library would work like this (Expecting you have added js.cookie.js before your code to your HTML)
// Store references to reusable selectors
var $menuAction = $('#menu-action');
var $menuActionI = $menuAction.find('i'); // the <i> inside #menu-action
var $sidebar = $('.sidebar');
var activeClass = 'active';
// Docs: https://github.com/js-cookie/js-cookie/tree/v2.1.0#basic-usage
var isActive = Cookies.get('site-menu-active') || false;
function toggleMenu() {
$sidebar.toggleClass('active', isActive);
$('.main').toggleClass('active', isActive);
$menuAction.toggleClass('active', isActive);
$menuActionI.toggleClass('fa-close', isActive);
$menuActionI.toggleClass('fa-bars', isActive);
isActive = !isActive;
Cookies.set('site-menu-active', isActive, { expires: 7 });
}
// Calling immediately to set to state read from cookie
toggleMenu();
// Add click interaction
$menuAction.click(toggleMenu);
// Add hover feedback on menu
$menuAction.hover(function() {
$sidebar.toggleClass('hovered');
});
The Html5 storage is the best option for these scenario. Here you can change the localStorage to sessionStorage based on the requirement:
1)localStorage - even close the browser the data is alive
2)sessionStorage - while close the browser the data is removed
We can also remove the stored data
$('#menu-action').click(function() {
$('.sidebar').toggleClass('active');
$('.main').toggleClass('active');
$(this).toggleClass('active');
localStorage.setItem("active", $('.sidebar').hasClass('active'));
if ($('.sidebar').hasClass('active')) {
$(this).find('i').addClass('fa-close');
$(this).find('i').removeClass('fa-bars');
} else {
$(this).find('i').addClass('fa-bars');
$(this).find('i').removeClass('fa-close');
}
});
$(document).ready(function(){
if(localStorage.getItem("active")){
$('.sidebar').addClass('active');
$('.main').addClass('active');
$('#menu-action').find('i').addClass('fa-close');
$('#menu-action').find('i').removeClass('fa-bars');
}
});
hi to all I'm new in js sorry for what I ask here now I know its a basic one, I'm working now with accordion plugin that collects all the article that users want to put in accordion and view it in accordion my question is how to open specific tab when is have dynamic id per article inside a item of accordion.. im trying to hook the item using link, http//:example.com#id to open specific tab in accordion here s the plugin code.
hook inside the code and trigger the click event to open the specific the in the accordion plugin
!(function($){
$.fn.spAccordion = function(options){
var settings = $.extend({
hidefirst: 0
}, options);
return this.each(function(){
var $items = $(this).find('>div');
var $handlers = $items.find('.toggler');
var $panels = $items.find('.sp-accordion-container');
if( settings.hidefirst === 1 )
{
$panels.hide().first();
}
else
{
$handlers.first().addClass('active');
$panels.hide().first().slideDown();
}
$handlers.on('click', function(){
if( $(this).hasClass('active') )
{
$(this).removeClass('active');
$panels.slideUp();
}
else
{
$handlers.removeClass('active');
$panels.slideUp();
$(this).addClass('active').parent().find('.sp-accordion-container').slideDown();
}
event.preventDefault();
});
});
};
})(jQuery);
A little thing is, you can use .children('div') instead of .find('>div').
But if you want to get what the hash is set to you can use window.location.hash. By default this is used to identify element IDs. So ideally you could get the element you want to show by doing
if (window.location.hash) {
var $selected = $('#'+window.location.hash);
if ($selected.length) {
// Do what you need to show this element
}
}
I have a swipe to do back script for my ios web app that I have running across every page but what I want to know how is to exclude from affecting the first page that shows up. The script is this
<script>
$(document).bind('swiperight', function () {
history.back();
});</script>
How would exclude a page that has a hypothetical id of "home"?
I'm assuming you're using jQuery mobile (Apologies if you're not), you could use $.mobile.activePage to check if you're at home:
http://jquerymobile.com/demos/1.2.0/docs/api/methods.html (At the bottom)
<script>
$(document).bind('swiperight', function () {
if ( $.mobile.activePage !== 'home' )
history.back();
});
</script>
The general principle would be this:
<script>
var id = // get your hypothetical id from somewhere;
if(id !== "home") {
$(document).bind('swiperight', function () {
history.back();
});
}
</script>
Without any more information on where the hypothetical id is coming from it's difficult to be more specific than that.
$(document).bind('swiperight', function () {
if (!$('body#home').length === 0) {
history.back();
// ... anything else
}
});
You could also use: if (!$('#page.home').length === 0) if it's going to be a class on a containing element, if ($('#page').hasClass('home')) is a bit more of solid jQuery-y way of doing it too.
I'm not the best when it comes to JavaScript, and stuck with finding a solution. I have seen similar questions asked here, but when I try to implement it in my case it either breaks the menu or just makes no difference.
I'm trying to get a menu (which opens on a click), to close not only with a repeated click on parent menu tab, but with a click outside the menu, i.e., anywhere.
My code is:
var toggleUpdatesPulldown = function(event, element, user_id) {
if( element.className=='updates_pulldown' ) {
element.className= 'updates_pulldown_active';
showNotifications();
} else {
element.className='updates_pulldown';
}
}
This snippet is in the middle of a lot more JavaScript and this is the default working version. The click from user changes the class name of the menu container which determines if it's displayed or not. From another post on here, I tried implementing the following to no avail to try and allow the click off to alter the class name as well:
var toggleUpdatesPulldown = function(event, element, user_id) {
if( element.className=='updates_pulldown' ) {
element.className= 'updates_pulldown_active';
showNotifications();
} else {
element.className='updates_pulldown';
}
ev.stopPropagation();
$(document).one('click', function() {
element.className='updates_pulldown';
});
}
Any advice on tackling this? I'd like to learn more JavaScript as I seem to be working with it more and more.
I hope you are still looking for a solution. Here's a working demo of this http://jsfiddle.net/sU9ZJ/6/
(function(win, doc) {
var lis = $('#menu>ul>li>a').on('click', function(e) {
e.preventDefault();
var a = $(this);
var li = $(this).parent();
function close(dev) {
if (!(dev && li.has(dev.target)[0])) {
li.addClass('inactive').removeClass('active');
doc.off('click', close);
a.trigger('close');
}
}
function open(dev) {
li.addClass('active');
doc.on('click', close);
a.trigger('open');
}
if (li.hasClass('active')) { close() }
else { open(); }
})
})(this, $(document))
I have also added a couple of events that you can use when it opens or closes
$('#menu>ul>li>a').on('open', function(e) {
console.log('menu open', this)
}).on('close', function(e) {
console.log('menu closed', this)
})
Sorry, this depends on jQuery. too lazy to write a native version :). Also this is not tested in IE, but shouldn't be too hard to make it work on those if it doesn't.