frcake frcake - 1 month ago 17
CSS Question

javascript sidebar stay open on page change

im a bit of a newbie on JS stuff , mostly use bootstrap ready solutions , but now i want to implement a sidebar for my facets(filtering).

So clicking on a filter , the content is changed based on that and the page URL as well , so the sidebar closes.

What I'd like to do , is the sidebar to stay open until the user clicks the X..

I used W3School sidebar tutorial for this , so this is my code :

<div id="mySidenav" class="sidenav">
<a href="javascript:void(0)" class="closebtn" onclick="closeNav()">&times;</a>
<a href="#">About</a>
<a href="#">Services</a>
<a href="#">Clients</a>
<a href="#">Contact</a>
</div>

<!-- Use any element to open the sidenav -->
<span onclick="openNav()">open</span>


JavaScript:

/* Set the width of the side navigation to 250px and the left margin of the page content to 250px */
function openNav() {
document.getElementById("mySidenav").style.width = "250px";
document.getElementById("main").style.marginLeft = "250px";
}

/* Set the width of the side navigation to 0 and the left margin of the page content to 0 */
function closeNav() {
document.getElementById("mySidenav").style.width = "0";
document.getElementById("main").style.marginLeft = "0";
}


CSS

/* The side navigation menu */
.sidenav {

height: 100%; /* 100% Full-height */
width: 0; /* 0 width - change this with JavaScript */
position: fixed; /* Stay in place */
z-index: 1; /* Stay on top */
top: 0;
left: 0;
background-color: #111; /* Black*/
overflow-x: hidden; /* Disable horizontal scroll */
padding-top: 60px; /* Place content 60px from the top */
transition: 0.5s; /* 0.5 second transition effect to slide in the sidenav */
}

/* The navigation menu links */
.sidenav a {
font-size: 20px;
padding:5px 10px 5px 10px;
text-decoration: none !important;
color: #818181;
background: transparent;
display: block;
transition: 0.3s
}

/* When you mouse over the navigation links, change their color */
.sidenav a:hover, .offcanvas a:focus{
color: #f1f1f1;
}

/* Position and style the close button (top right corner) */
.sidenav .closebtn {
position: absolute;
top: 0;
right: 25px;
font-size: 36px;
margin-left: 50px;
}

.sidenav .removebtn {
color: #e9e9e9;
position: absolute;
top: 0;
left: 25px;
font-size: 20px;
margin-right: 50px;
}

/* Style page content - use this if you want to push the page content to the right when you open the side navigation */
#main {
transition: margin-left .5s;
padding: 20px;
}

/* On smaller screens, where height is less than 450px, change the style of the sidenav (less padding and a smaller font size) */
@media screen and (max-height: 450px) {
.sidenav {padding-top: 15px;}
.sidenav a {font-size: 18px;}
}


I saw some solutions including Cookies , but being a noob in JS stuff , i'd like an answer i can understand.

Thank you!

Answer

So if I understand correctly, you want to keep the bar open when the page change.

When the page reloads into an other one, the browser gets a new html from the server (even if it is the same), and the hole page resets, so the side bar state resets.

You can save the state of the side bar somewhere so that you can retrieve it once the page loads again. Javascript has access to 2 storages, the Cookies and the LocalStorage.

Cookies are shared with the server (the browser sends all the cookies to the server with each request) while the localStorage can be accested only by the javascript.

The server usually don't care if the sidebar is opened or closed, so the "right" storage to use is the localStorage. (LocalStorage in w3schools http://www.w3schools.com/html/html5_webstorage.asp)

To your problem now,

You need to save the sidebar state, so you update the state when you close or open the sidebar :

function openNav() {
    ...
    // If localStorage is supported by the browser
    if (typeof(Storage) !== "undefined") {
        // Save the state of the sidebar as "open"
        localStorage.setItem("sidebar", "opened");
    }
    ...
}

function closeNav() {
    ...
    // If localStorage is supported by the browser
    if (typeof(Storage) !== "undefined") {
        // Save the state of the sidebar as "open"
        localStorage.setItem("sidebar", "closed");
    }
    ...
}

Now that we have saved the state, we need to check it every time the browser loads the page. We need to do it fast, so we don't want to wait for any event like onload event. We only need the sidebar element to be loaded on the page, not all the page, so we can enter our code right under the sidebar element.

<!-- The sidebar element -->
<div id="mySidenav" class="sidenav">...</div>
<!-- Right after the browser renders the sidebar -->
<script type="text/javascript">
    // If localStorage is supported by the browser
    if (typeof(Storage) !== "undefined") {
        // If we need to open the bar
        if(localStorage.getItem("sidebar") == "opened"){
            // Open the bar
            document.getElementById("mySidenav").style.width = "250px";
            document.getElementById("main").style.marginLeft = "250px";
        }
    }
</script>

This has 2 problems,

  1. LocalStorage has to be supported. (Google Chrome 4.0+, Internet Explorer 8.0+, Firefox 3.5+, Safari 4.0+, Opera 11.5+)
  2. It replays the animation due to the transition: .5s; css rule.

The 2nd problem can be fixed by adding the transition: .5s; on a class and temporary removing it with javascript untill you open the sidebar.

<!-- The sidebar element -->
<div id="mySidenav" class="sidenav">...</div>
<!-- Right after the browser renders the sidebar -->
<script type="text/javascript">
    // If localStorage is supported by the browser
    if (typeof(Storage) !== "undefined") {
        // If we need to open the bar
        if(localStorage.getItem("sidebar") == "opened"){
            // Remove class with transition from the 'sidebar' and the 'main'
            ...
            // Open the bar
            document.getElementById("mySidenav").style.width = "250px";
            document.getElementById("main").style.marginLeft = "250px";
            // Add the transition class again
            ...
        }
    }
</script>

Using Cookies

Javascript don't access the cookies in the same way like the access to the local storage.

You can imagine cookies like a big string that can be accessed from the variable on document.cookie (all document cookies are here)

You can see this variable in the console

> document.cookie
"a_cookie_name=cookie_value; an_other_cookie_name=and_his_value; ..."

To save a cookie, all you have to do is

// Add/Update a cookie by name
document.cookie = name + "=" + value + ";"

This doesn't clear the old cookies, it only adds a new cookie or if it exist, it updates it.

But it is a little difficult to get their value... you have to get the string in a variable, split the string in "; " so that you have an array of string where each item of the array is a cookie, and search for your cookie in the array... too big trouble.

But we don't have to reinvent the wheal... so we can use w3schools' code

function setCookie(cname, cvalue, exdays) {
    var d = new Date();
    d.setTime(d.getTime() + (exdays*24*60*60*1000));
    var expires = "expires="+d.toUTCString();
    document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}

function getCookie(cname) {
    var name = cname + "=";
    var ca = document.cookie.split(';');
    for(var i = 0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) == ' ') {
            c = c.substring(1);
        }
        if (c.indexOf(name) == 0) {
            return c.substring(name.length, c.length);
        }
    }
    return "";
}

Now insted of using localStorage we use the functions above

localStorage.getItem("sidebar") equivalent is getCookie("sidebar")

localStorage.setItem("sidebar","<value>") equivalent is setCookie("sidebar", "<value>", 30)

(note that because the cookies expire, we set it to expire after 30 days, so to delete a cookie, you set the expiration day to a time before now)

It good to check more about cookies on w3schools and the localStorage.