Keep menu toggle state after page reload - javascript

Here’s a toggle menu who works perfectly:
If I click on the link (HTML code below), the menu folds. But I want if the users reload the page to keep the state of menu (expand / collapse).
$('#menu_toggle').click(function () {
if ($('body').hasClass('nav-md')) {
$('body').removeClass('nav-md');
$('body').addClass('nav-sm');
$('.left_col').removeClass('scroll-view');
$('.left_col').removeAttr('style');
$('.sidebar-footer').hide();
if ($('#sidebar-menu li').hasClass('active')) {
$('#sidebar-menu li.active').addClass('active-sm');
$('#sidebar-menu li.active').removeClass('active');
}
} else {
$('body').removeClass('nav-sm');
$('body').addClass('nav-md');
$('.sidebar-footer').show();
if ($('#sidebar-menu li').hasClass('active-sm')) {
$('#sidebar-menu li.active-sm').addClass('active');
$('#sidebar-menu li.active-sm').removeClass('active-sm');
}
}
});
<a id="menu_toggle"><i class="fa fa-bars"></i></a>
How to remember the state?
Full project: http://demo.kimlabs.com/gentelella/production/index.html
Thanks

You should use cookies to store booleans, of if the menu has been opened or closed. Then when a page is loaded, it checks for any stored cookies, and by default uses those variables.
For example:
on page load:
var menuOutBoolean = Cookies.get("menuOutB") || false;
if (menuOutBoolean == true || menuOutBoolean == "true"){
//put the menu out
}
else {
//put menu in
}
On change:
if (/*out*/){
Cookies.set("menuOutB","true");
}
else{
Cookies.set("menuOutB","false");
}
Note:
Here I have used this JavaScript API (Jquery Plugin).

This is the sort of thing I'd use localStorage for. Just set some kind of flag in localStorage when the state changes and fetch it when your page loads.
I should add that using css classes to represent view state isn't a good idea and will bite you if your UI gets much more complicated.

Related

Checking to see if an element exists on a page, if so execute a function and if not do nothing

Here is the scenario: I have 2 sets of navigation, main and secondary. The main navigation will always exist on a page and the secondary nav will not always be present. On the pages that DO contain the secondary nav, I want the main navigation to do something on mouseenter and mouseleave only when a class of "affix" has been attached to the secondary nav (after the page has been scrolled down to a certain point, but that is a separate piece of code).
The code I currently have is as follows:
var navItem = $('.main-navigation');
var stickyNav = $('.tabbed-sticky-nav.affix');
if (stickyNav == null || stickyNav == 'undefined') {
doNothing();
return;
} else {
navItem.mouseenter(function() {
console.log("Hover");
});
navItem.mouseleave(function() {
console.log("Out");
});
}
function doNothing() {
console.log("Object not found");
}
When I run this as it is, the nav items always fire the code whether or not the subnav is on the page. I should probably be first checking if .tabbed-sticky-nav exists on the page, that way if the page doesn't have the secondary nav then don't bother checking for anything on hover. However, if the .tabbed-sticky-nav DOES exist and has the class of "affix" added to it, only then do I want the hover actions of the main nav to potentially apply. How can I change things so this cleanly checks and executes for these circumstances?
jQuery always returns something, so the way to check if the elements exist is to use the length property. That will tell you how many elements were returned by the given selector.
if (!stickyNav.length){
...
}

History API with jQuery - address bar changes but doesn't refresh divs

I've been able to easily use the history.pushState to change the content of my div and have the address bar reflect a fake url. However, whenever I push the back/forward buttons the url changes back but the content remains the same. Typing in the url comes up with an error. It seems I have the first part of the history API down, but need help doing state changes.
I'm a fairly new programmer and trying to build my website in jQuery and keep the code as concise as possible.
HTML code:
<ul>
<li><button class="navButton" id="signUp" href="./content/registration.php" name="registration" title="Registration">Sign Up</button></li>
<li><button class="navButton" id="settings" href="./content/account_settings.php" name="settings" title="settings">Settings</button></li>
<li><button class="navButton" id="about" href="./content/about.php" name="about" title="About">About</button></li>
</ul>
<div id="mainContent"></div>
Javascript code:
$(document).ready(function() {
// INITIAL CONTENT ON FIRST LOAD
$("#mainContent").load('./content/start.php');
// CODE FROM HISTORY.JS
(function(window, undefined) {
var History = window.History;
if (!History.enabled) {
return false;
}
History.Adapter.bind(window, 'statechange', function() {
var State = History.getState();
History.log(State.data, State.title, State.url);
});
// EVENT LISTENER FOR NAVBUTTON CLASS TO REPLACE CONTENT IN MAINCONTENT DIV
$('.navButton').click(function(e) {
e.preventDefault();
pageurl = $(this).attr('name');
$("#mainContent").fadeOut().load($(this).attr("href")).fadeIn();
if (pageurl != window.location) {
history.pushState('', $(this).attr('title'), $(this).attr('name'));
}
});
})(window);
});
I have installed history.js but if I don't need to use it, that would be preferred. I would love to have this code corrected so the back button refreshes and this works!
So I solved this by adding an if statement under the popstate to compare the url and determine the content loaded in the mainContent div. Works!.. but discovered my original pushstate is pushing several popstates the more you click the navButtons. That question is posted Cannot find where I have a popstate loop creating multiple history entries
window.addEventListener('popstate', function() {
//WHEN BACK/FORWARD CLICKED CHECKS URL PATHNAME TO DETERMINE WHICH CONTENT TO PLACE IN DIV
if (location.pathname == "/index.php") {
$("#mainContent").load("./content/start.php");
} else {
$("#mainContent").load("./content" + location.pathname + ".php");
}
});
Advice: use the built html5 history state, to pass in objects or params or so on...
Action when you are pushing a state into browser:
history.pushState('{url:location}', $(this).attr('title'), $(this).attr('name'));
Action when your clicked back or front using the browser:
$(window).on('popstate', function(e){
if(e.originalEvent.state != null){
console.log("url to render"+e.originalEvent.state.url)
}else{
console.log("nothing in the state, do nothing")
}

Having trouble maintaining state on custom jQuery menu

Check out the treatments menu on right hand side of this website. It has a set of <dt> tags with an <a> tag and a <ul> list of submenu <li> links inside. The top level link and sumbmenu links are grouped together using the rel attribute.
As you can see the submenu slides down when you click the top level link. What I'm trying to do is maintain state between page loads so that if any of the links in the submenus are clicked it will stay open. I am trying to use the rel attribute to do this.
Here is my code so far, I am getting a bit confused with the logic:
function initMenu() {
$('.menu ul:not(.active)').hide();
var checkCookie = $.cookie("nav-item");
if (checkCookie != "") {
$('.menu').each(function () {
var state = $(this).find('a:first-child').attr('rel');
if (state == checkCookie) {
alert(state);
$(this).next().slideToggle('normal');
}
})
}
$('.menu > a:first-child').click(function(e) {
e.preventDefault();
var navIndex = $(this).attr('rel');
$.cookie("nav-item", navIndex);
$(this).next().slideToggle('normal');
});
}
$(function() {
initMenu();
});
EDIT**
I have changed the first part of the code to this in order to try and use the active class. But what its doing is opening all the ul's instead of just the ul that contains the li with the active class.
$('.menu ul:not(.active)').hide();
$('.menu').each(function (){
if ($(this).children(".active")){
$(this).children('ul').slideToggle('normal');
}
});
Update *after update of original question*
Use for the if
if ($(this).find(".active").length){
$(this).children('ul').slideToggle('normal');
}
Original answer
One thing is with
if (state == checkCookie) {
alert(state);
$(this).next().slideToggle('normal');
}
this in this context refers to .menu and not the a link.
You should change it to
if (state == checkCookie) {
alert(state);
$(this).children('ul').slideToggle('normal');
}
The other is that the cookie plugin creates (by default) cookies that belong to the page that created them. So when you change a page it does not have access to a cookie created by another page.
Use the path option when saving $.cookie("nav-item", navIndex, {path: '/'});
The correct way
It would be best though not to rely on cookies for navigation as it will become problematic when a user starts using the back button ..
You should really pass the rel value to the url as the hash #relvalue and use that instead.
(hint: check out window.location.hash)

js: hiding divs

I am pretty new to Javascript so please bear with me.
$('#bioContent').css('display','none');
$('#skillsContent').css('display','none');
$('#credsTab').css('background-color','#fff');
$('#credsTab a').css('color','#19d700');
$('#bioTab').css('background-color','#ccc');
$('#bioTab a').css('color','#444');
$('#skillsTab').css('background-color','#ccc');
$('#skillsTab a').css('color','#444');
$('#credsTab').click(function(){
$('#credsContent').css('display','block');
$('#bioContent').css('display','none');
$('#skillsContent').css('display','none');
$('#credsTab').css('background-color','#fff');
$('#credsTab a').css('color','#19d700');
$('#bioTab').css('background-color','#ccc');
$('#bioTab a').css('color','#444');
$('#skillsTab').css('background-color','#ccc');
$('#skillsTab a').css('color','#444');
})
$('#bioTab').click(function(){
$('#bioContent').css('display','block');
$('#credsContent').css('display','none');
$('#skillsContent').css('display','none');
$('#bioTab').css('background-color','#fff');
$('#bioTab a').css('color','#19d700');
$('#credsTab').css('background-color','#ccc');
$('#credsTab a').css('color','#444');
$('#skillsTab').css('background-color','#ccc');
$('#skillsTab a').css('color','#444');
})
$('#skillsTab').click(function(){
$('#skillsContent').css('display','block');
$('#bioContent').css('display','none');
$('#credsContent').css('display','none');
$('#skillsTab').css('background-color','#fff');
$('#skillsTab a').css('color','#19d700');
$('#bioTab').css('background-color','#ccc');
$('#bioTab a').css('color','#444');
$('#credsTab').css('background-color','#ccc');
$('#credsTab a').css('color','#444');
})
That's my javascript implementation of tabs. Basically on click, divs hide away and others appear.
My problem with this is that on the skillsTab, there's an add skills method, and when I click on that, it refreshes the page, and when it does, it brings me back to the credsTab, the default when the page is loaded.
I was wondering if that's a way so that when it refreshes, it will stay on the skillsTab.
Keep state around, which can be done via fragment URLs or HTML5 history.
e.g., make opening up the skills tab change the fragment to #skills, which will remain across a refresh. Then check window.location.hash in your onLoad to determine what initial state your page should be in.
function switchToTab(tabName) {
// DOM/CSS manipulation etc. here
}
var tabs = ['bio', 'skills', 'creds'];
var initialTab = 'bio';
for (var i = 0; i < tabs.length; i++) {
(function(tabName) {
document.getElementById(tabName + 'Tab').addEventListener('click', function() {
switchToTab(tabName);
location.hash = '#' + tabName;
}, false);
})(tabs[i]);
}
window.addEventListener('load', function() {
if (location.hash[0] == '#')
switchToTab(location.hash.substr(1));
}, false);
window.addEventListener('hashchange', function() {
if (location.hash[0] == '#')
switchToTab(location.hash.substr(1));
else
switchToTab(initialTab);
}, false);
Untested, and there's plenty of JS libraries out there that abstract this away for you.
An initial suggestion. give all your tabs the same class, maybe class='toggleableTab' then you can use
$('.togglableTab').live('click',function(){
$('.togglableTab').not(this).hide();
$(this).show();
});
as for the page refresh. Look into using AJAX to "add" your skills live on the page without a full page refresh.
There are several tabbed solutions already in place that you could make use of - for example, http://jqueryui.com/demos/tabs/. JQuery UI is a great way to have a lot of this work done for you.
If you want to do it yourself, I would also suggest a solution using classes, but slightly different than other suggestions. Instead, have two classes, "activeTab" and "tabbable". In your css, define "activeTab" as visible, and "tabbable" as hidden. Give each tab an ID and the class of "tabbable". Have a hidden field in your form called "activeTabId". Make sure that this gets passed back from the server side when you load the page, including setting it to the default tab when you first load the page. You could then run the following code on page load to make it all play well together:
$(".tabbable").click(new function(){
$(".tabbable").removeClass("activeTab");
$(this).addClass("activeTab");
$("#activeTabId").val($(this).attr("id"));
});
$("#" + $("#activeTabId").val()).addClass("activeTab");

javascript variables not setting - checked via firebug

I'm new to stackoverflow!
I'm having problems with a piece of code for my companies website, using jquery. I'm trying to track the clicks on two button and set a variable/s which can then be used to determine a course of action. Basically its a sliding dropdown that animates one way if the variable is set to true and another if it is set to false. I've initiallised the variables both to be false to begin with and then through the course of clicking they should be set to true or false depending on the situation:
var boollogin = false;
var boolregister = false;
$(document).ready(function(){
$('#slidedownlogin').hide();
$('#details_add_area').hide();
$('#emailconfirmation').hide();
$('#register').toggle(function(){
if(boollogin == false){
$('#login_area').hide();
$('#register_area').show();
$('#details_add_area').hide();
$('#slidedownlogin').animate({'height':'235px'},1500, 'easeOutExpo');
}else{
$('#slidedownlogin').animate({'height':'0px'},1500, 'easeOutExpo',function(){
$('#login_area').hide();
$('#details_add_area').hide();
$('#register_area').show();
$('#slidedownlogin').animate({'height':'235px'},1500, 'easeOutExpo');
});
}
boolregister = true;
} , function(){
$('#slidedownlogin').animate({'height':'0px'},1500, 'easeOutExpo', function(){
$('#slidedownlogin').children().hide();
});
boolregister = false;
boollogin = false;
});
$('#login').toggle(function(){
if(boolregister == false){
$('#register_area').hide();
$('#details_add_area').hide();
$('#login_area').show();
$('#slidedownlogin').animate({'height':'220px'},1500, 'easeOutExpo');
}else{
$('#slidedownlogin').animate({'height':'0px'},1500, 'easeOutExpo',function(){
$('#register_area').hide();
$('#details_add_area').hide();
$('#login_area').show();
$('#slidedownlogin').animate({'height':'220px'},1500, 'easeOutExpo');
});
}
boollogin = true;
} , function(){
$('#slidedownlogin').animate({'height':'0px'},1500, 'easeOutExpo', function(){
$('#slidedownlogin').children().hide();
});
boollogin = false;
boolregister= false;
});
});
The page I'm working on is at http://www.premiersoftware.co.uk/index94.php. Full code is in the php file at the moment so you can look at it there too. You should be able to get an idea of what I'm trying to do by clicking the two links (Register and Login) at the top right of the page.These are supposed to reset the variables boollogin or boolregister, but inspecting these two variables in firebug reveals they aren't being reset and don't change. As a result the page initially acts as expected but after a while and a few clicks it gets really quirky. The form valitation and stuff hasn't been done yet as I'm trying to get the animation sorted first.
I was hoping someone here would be able to shed some light on why the variables aren't being reset and suggest how I could fix the code. If there is another way to create the same kind of functionality I'm also open to suggestion.
Thanks in advance
Dan
I think instead of closing the div that drops down and then opening it up again when the user switches between login and register, it may be more intuitive to just display the correct register or login form within the opened div.
This code may help you regardless, but it implements what I suggested above.
http://jsbin.com/etezo5
edit link so you can see the code:
http://jsbin.com/etezo5/edit
have you tried doing something like:
$('Register').appendTo('#support').css({'float':'right','margin-right':'10px'});
$('Login').appendTo('#support').css({'float':'right','margin-right':'10px'});
Then in your JS,
function toggleTheCorrectDiv(toggleRegister){
if (toggleRegister){
//Show Register Content
}else{
//Show Login Content
}
}

Categories