O'Reilly logo

JavaScript Cookbook by Shelley Powers

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

8.8. Bookmarking a Dynamic Page

Problem

You have a dynamic application in which updates occur in the page rather than when the page refreshes. You want to provide a link to your web page reader that not only takes the user back to the page, but returns it to a given state.

Solution

Use the Location object’s hash property in order to return to the state directly:

var someval = window.location.hash.split("#")[1];
if (someval == "state1") {
...
}

Discussion

A page fragment (#somevalue) isn’t just a way to annotate an in-page link; it can also be a way to restore a state for an application. If dynamic effects are being made in a web page, and you want to preserve state at any time in such a way that a person can return to that state, you can create a unique hash for it and then provide the link to your web page reader.

To demonstrate, Example 8-2 is a web page that has a div wrapping a button and another div, and which changes various CSS-style property attributes with each click of the button. Since we want to give the web page reader the ability to return to a state at any time, a link is generated for that the person.

Why don’t I use a stylesheet class and change the class name, rather than set the attributes individually? And why call all of the functions in order, rather than directly call each one? The reason is I’m building on the style settings from each previous function call, rather than resetting the style with each. If I used a class setting with the values, the results would be vastly different, because the style attributes not set would be returned to their inherited values. That’s the major difference between using a class setting and changing individual style attributes.

Example 8-2. Preserving page state through hash on link

<!DOCTYPE html>
<head>
<title>Remember me?</title>
<script>

   window.onload=function() {

      // set up button
      document.getElementById("next").onclick=nextPanel;

      // check for hash, if found, reload state
      var hash = window.location.hash.split("#")[1];
      switch (hash) {
        case "one" :
           functionOne();
           break;
        case "two" :
           functionOne();
           functionTwo();
           break;
        case "three" :
           functionOne();
           functionTwo();
           functionThree();
      }

   }

   // display next panel, based on button's class
   function nextPanel() {
      var classNm = this.getAttribute("class");
      switch(classNm) {
         case "zero" :
            functionOne();
            break;
         case "one" :
            functionTwo();
            break;
         case "two" :
            functionThree();
       }
   }
   // set both the button class, and create the state link,
   // add to page
   function setPage(page) {
      document.getElementById("next").setAttribute("class",page);
      var link = document.getElementById("link");
      var path = location.protocol + "//" + location.hostname + "/" +
                 location.pathname + "#" + page;
      link.innerHTML="<p><a href='" + path + "'>link</a></p>";

   }

   // function one, two, three - change div, set button and link
   function functionOne() {
      var square = document.getElementById("square");
      square.style.backgroundColor="#ff0000";
      square.style.width="200px";
      square.style.height="200px";
      square.style.padding="10px";
      square.style.margin="20px";
      setPage("one");
   }

   function functionTwo() {
      var square = document.getElementById("square");
      square.style.backgroundColor="#ffff00";
      square.style.position="absolute";
      square.style.left="200px";
      setPage("two");
   }

   function functionThree() {
      var square = document.getElementById("square");
      square.style.width="400px";
      square.style.height="400px";
      square.style.backgroundColor="#00ff00";
      square.style.left="400px";
      setPage("three");
   }
</script>
</head>
<body>
<button id="next" class="zero">Next Action</button>
<div id="square">
<p>This is the object</p>
<div id="link"></div>
</div>
</body>

In the code, if there is a hash mark given in the window.object, the functions to set the state of the page are called. Since, in this example, each is dependent on what’s happened in the other state functions, they’ll need to be called before the end state. So if the hash mark is three (#three), both functionOne and functionTwo need to be called before functionThree, or the div element’s state will be different (the style settings won’t be the same).

Note

The use of set- and getAttribute with the style attribute won’t work with IE7. The downloadable example contains a workaround.

See Also

Recipe 12.15 provides a detailed discussion about changing CSS properties for elements. Chapters 13 and 14 demonstrate other dynamic page effects created by setting CSS-style attributes or changing an element’s class name. Recipe 20.1 covers another example in which information can be persisted using the URL. Recipe 20.3 demonstrates state persistence using new HTML5 functionality.

Recipe 8.9 extends the concept of state from Example 8-2, so that the example can also work with page refreshes and after the use of the back button. Recipe 11.12 covers the getAttribute method.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required