Using Anchors in AJAX base web apps | Maurizio Conventi

Using Anchors in AJAX base web apps

In these years the use of AJAX calls and javascript in web pages is grown.
Javascript could be really useful to create web based apps, reduce loading time of pages and create fancy web pages.

Using javascript to change the contents in your pages could create big problems with the back button …I know, it’s always it ;)

Image if your user:
- opens a section loaded using an AJAX call (but also only to show/hide contents)
- then shows an other section
- then clicks on the back button

…ouch…your user’s browser doesn’t remember her actions!

See the following example

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>

    <style>
        .hidden {display:none;}
    </style>
    <script type="text/javascript">
        var showSection = function(p_section_id){
            var section = document.getElementById(p_section_id);

            if (hasClass(section, 'hidden')) {
                hideOpenSections();
                removeClass(section, 'hidden');
            }

            return false;
        }
        // Hides all the open sections
        var hideOpenSections = function(){
            var sections = document.getElementsByTagName("p");

            for(var i=0; i < sections.length; i++) {
              if (hasClass(sections[i], 'section') && !hasClass(sections[i], 'hidden')) {
                  addClass(sections[i], 'hidden');
              }
            }
        }
        // Uses a regular expression to check if an element has a class
        var hasClass = function(p_element, p_class_name){
            return new RegExp('\\b'+p_class_name+'\\b').test(p_element.className)
        }
        // Removes a class from an element
        var removeClass = function(p_element, p_class_name){
            var rep=p_element.className.match(' '+p_class_name)?' '+p_class_name:p_class_name;
            p_element.className=p_element.className.replace(rep,'');
        }
        // Adds a class to an element
        var addClass = function(p_element, p_class_name){
            p_element.className += ' ' + p_class_name;
        }
    </script>
  </head>
  <body>
    <div>
        <h2><a href="." onclick="return showSection('section_a');">Section A</a></h2>
        <p id="section_a" class="section">
            This is the content for the section A
        </p>
    </div>
    <div>
        <h2><a href="." onclick="return showSection('section_b');">Section B</a></h2>
        <p id="section_b" class="section hidden">
            This is the content for the section B
        </p>
    </div>
    <div>
        <h2><a href="." onclick="return showSection('section_c');">Section C</a></h2>
        <p id="section_c" class="section hidden">
            This is the content for the section C
        </p>
    </div>
  </body>
</html>

(note, I didn't use js libraries to give you a simple generic example but I am sure you can use your favorite js library ;)

Now we are going to see how Anchors can help us.
See this new example:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>

    <style>
        .hidden {display:none;}
    </style>
    <script type="text/javascript">
        var init = function(){
            setInterval("checkSection()", 400);
        }

        // Every 400ms checks if the section currently showed is the right one
        var checkSection = function(p_section_id){
            current_anchor = document.location.hash.substring(1);

            var section = document.getElementById(current_anchor);
            if (section && hasClass(section, 'hidden')) {
                hideOpenSections();
                removeClass(section, 'hidden');
            }
        }
        // Hides all the open sections
        var hideOpenSections = function(){
            var sections = document.getElementsByTagName("p");

            for(var i=0; i < sections.length; i++) {
              if (hasClass(sections[i], 'section') && !hasClass(sections[i], 'hidden')) {
                  addClass(sections[i], 'hidden');
              }
            }
        }
        // Uses a regular expression to check if an element has a class
        var hasClass = function(p_element, p_class_name){
            return new RegExp('\\b'+p_class_name+'\\b').test(p_element.className)
        }
        // Removes a class from an element
        var removeClass = function(p_element, p_class_name){
            var rep=p_element.className.match(' '+p_class_name)?' '+p_class_name:p_class_name;
            p_element.className=p_element.className.replace(rep,'');
        }
        // Adds a class to an element
        var addClass = function(p_element, p_class_name){
            p_element.className += ' ' + p_class_name;
        }
    </script>
  </head>
  <body onload="init()">
    <div>
        <h2><a href="#section_a">Section A</a></h2>
        <p id="section_a" class="section">
            This is the content for the section A
        </p>
    </div>
    <div>
        <h2><a href="#section_b">Section B</a></h2>
        <p id="section_b" class="section hidden">
            This is the content for the section B
        </p>
    </div>
    <div>
        <h2><a href="#section_c">Section C</a></h2>
        <p id="section_c" class="section hidden">
            This is the content for the section C
        </p>
    </div>
  </body>
</html>

What's the difference?
This last example uses a function that checks the anchor every 400ms. In this case we don't have a function called at the onclick event. The periodic function checks if the anchor is coherent with the currently opened section and in case opens the correct one.

Advantages: if you click on the back/forward button you'll have a coherent behavior. There is also a second advantage, we don't have js code in the html (also if you can obtain this last advantage even in other ways).

Naturally, suggestions  and comments are welcomed ;)

Tags: , ,

Leave a Reply

Your email address will not be published. Required fields are marked *

*