SitePoint Sponsor

User Tag List

Results 1 to 7 of 7
  1. #1
    SitePoint Member
    Join Date
    Nov 2007
    Posts
    4
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Converting list-type menu links to unobtrusive JavaScript

    I bought the PDF copy of Sitepoint's Just JavaScript and find its explanations of JavaScript very straight forward, but I'm having great trouble coming to terms with event listeners etc.

    Is there an example someone can point me to that will help me understand how to convert a list-type menu item into unobtrusive JavaScript?

    I can learn quickly from a working example.

    I can find plenty of snippets, such as "fire off an onload function that will locate the id" etc. Sorry, I really need an example to learn from.

    Here's what I'm trying to do ...

    This is my code from a menu list:

    <li><a href="weather.php">Weather</a></li>

    I know I've got to give its <a> tag an id like this ...

    <li><a id="weather-link" href="weather.php">Weather</a></li>

    ... so that I can set up an Ajax call to some code on the server to replace the content of the appropriate <div> with the new stuff. If JavaScript is not enabled, I have an existing "weather.php" file for the site to operate normally.

    I can do Ajax calls all right, but it's getting from the 'id="weather-link" to the Ajax code that's got me beaten at present. How do I do it?

    I'm dedicated to switching to unobtrusive JavaScript, so any guidance would be much appreciated.

  2. #2
    SitePoint Author silver trophybronze trophy

    Join Date
    Nov 2004
    Location
    Ankh-Morpork
    Posts
    12,158
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Something like this?

    Code HTML4Strict:
    <ul id="links">
      <li><a href="weather.php">Weather</a></li>
      <li><a href="leather.php">Leather</a></li>
    </ul>

    Code JavaScript:
    (function () {
        var Links = {
            init: function () {
                      var ul = document.getElementById("links");
                      var a = ul.getElementsByTagName("a");
                      for (var i = 0, len = a.length; i < len; ++i) {
                          Links.addListener(a[i], "click", Links.showPage);
                      }
                  },
     
            addListener: function (element, eventName, listener) {
                             if (element.addEventListener) {
                                 element.addEventListener(eventName, listener, false);
                             } else if (element.attachEvent) {
                                 element.attachEvent("on" + eventName, listener);
                             } else {
                                 var old = element["on" + eventName];
                                 element["on" + eventName] = function (e) {
                                     if (old) old(e);
                                     listener(e);
                                 }
                             }
                         },
     
            showPage: function (e) {
                          var a = e ? e.target : window.event.srcElement;
                          doAjaxCall(a.href);
                          if (e) {
                              e.preventDefault();
                              e.stopPropagation();
                          } else if (window.event) {
                              window.event.returnValue = false;
                              window.event.cancelBubble = true;
                          } else {
                              return false;
                          }
                      }
        };
     
        Links.init();
    })();
    Birnam wood is come to Dunsinane

  3. #3
    Guru in training bronze trophy SoulScratch's Avatar
    Join Date
    Apr 2006
    Location
    Maryland
    Posts
    1,838
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Question for ya Tommy, what's the benefit of using the pre increment instead of the post increment? (++i vs ++i) ? My only guess is that it may be a tiny bit faster (not sure why though) and wouldn't there be some circumstances where the loop would not iterate through every item if you pre increment?

  4. #4
    SitePoint Author silver trophybronze trophy

    Join Date
    Nov 2004
    Location
    Ankh-Morpork
    Posts
    12,158
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by SoulScratch View Post
    Question for ya Tommy, what's the benefit of using the pre increment instead of the post increment? (++i vs ++i) ?
    I doubt there's any real benefit at all in JavaScript. It's just an old habit of mine from coding in C++. If you create complex objects and overload the increment operator for them, there can be significant differences if you use pre-increment instead of post-increment, since you don't have to create a copy to return. Especially if the constructor has side-effects (such as allocating memory or other resources), it can make a lot of difference.

    Quote Originally Posted by SoulScratch View Post
    wouldn't there be some circumstances where the loop would not iterate through every item if you pre increment?
    Not unless you manipulate the loop variable inside the loop, and that's no different if you use post-increment.

    Code:
    for (a; b; c)
        statement;
    This is equivalent to,
    Code:
    a;
    while (b) {
        statement;
        c;
    }
    Unless you actually use the return value, it doesn't matter whether you choose ++i or i++, although the former may be half a nanosecond faster.
    Birnam wood is come to Dunsinane

  5. #5
    Function Curry'er JimmyP's Avatar
    Join Date
    Aug 2007
    Location
    Brighton, UK
    Posts
    2,006
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by SoulScratch View Post
    Question for ya Tommy, what's the benefit of using the pre increment instead of the post increment? (++i vs ++i) ?
    Like Tommy said there is normally no real benefit but there is a difference in the processing as you probably know.

    In the following code "numCopy" would equal to 10:
    Code JavaScript:
    var num = 10;
    var numCopy = num++;

    But in this piece of code it would equal to 11:
    Code JavaScript:
    var num = 10;
    var numCopy = ++num;

    So I guess the only reason you would need to pre-increment is if you want to increment a variable and read it's value at the same time... although such a thing can be completed in two steps anyway so there's no real point. < - Like tommy said about using it's return value.
    James Padolsey
    末末末末末末末末末末末末末末末末末末末
    Awesome JavaScript Zoomer (demo here)
    'Ajaxy' - Ajax integration solution (demo here)

  6. #6
    SitePoint Member
    Join Date
    Nov 2007
    Posts
    4
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by AutisticCuckoo View Post
    Something like this?

    Code HTML4Strict:
    <ul id="links">
      <li><a href="weather.php">Weather</a></li>
      <li><a href="leather.php">Leather</a></li>
    </ul>

    Code JavaScript:
    (function () {
        var Links = {
            init: function () {
                      var ul = document.getElementById("links");
                      var a = ul.getElementsByTagName("a");
                      for (var i = 0, len = a.length; i < len; ++i) {
                          Links.addListener(a[i], "click", Links.showPage);
                      }
                  },
     
            addListener: function (element, eventName, listener) {
                             if (element.addEventListener) {
                                 element.addEventListener(eventName, listener, false);
                             } else if (element.attachEvent) {
                                 element.attachEvent("on" + eventName, listener);
                             } else {
                                 var old = element["on" + eventName];
                                 element["on" + eventName] = function (e) {
                                     if (old) old(e);
                                     listener(e);
                                 }
                             }
                         },
     
            showPage: function (e) {
                          var a = e ? e.target : window.event.srcElement;
                          doAjaxCall(a.href);
                          if (e) {
                              e.preventDefault();
                              e.stopPropagation();
                          } else if (window.event) {
                              window.event.returnValue = false;
                              window.event.cancelBubble = true;
                          } else {
                              return false;
                          }
                      }
        };
     
        Links.init();
    })();
    Many thanks, AutisticCuckoo. It works like a dream!

    Just the stuff I needed. Now to the book again to get to understand it thoroughly line by line.

    I cannot recommend Simply JavaScript and your forums too highly.

  7. #7
    SitePoint Author silver trophybronze trophy

    Join Date
    Nov 2004
    Location
    Ankh-Morpork
    Posts
    12,158
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by JimmyP View Post
    So I guess the only reason you would need to pre-increment is if you want to increment a variable and read it's value at the same time...
    I see it the other way: the only reason for post-increment is if you need the value before it's incremented. Post-increment is less efficient than pre-increment, since it requires making a copy of the value. You could envision it as something like this:
    Code:
    int post-increment(int& x) {
      int y = x;
      x = x + 1;
      return y;
    }
    
    int pre-increment(int& x) {
      return x = x + 1;
    }
    Quote Originally Posted by TallTrees View Post
    Now to the book again to get to understand it thoroughly line by line.
    Links is an object literal with three functions.

    The init() function looks for an element with id="links" and then retrieves all its descendant <a> elements. The return value from getElementsByTagName() is a NodeList, not an array. The function loops over all items in the NodeList and attaches an event listener for the click event to each one. The listener is the showPage() function in the Links object, and it's attached using the addListener() helper function.

    addListener() encapsulates the differences between browsers. DOM2-compliant browsers like Opera, Firefox, Safari, etc., use addEventListener(); Internet Explorer uses attachEvent(). Older browsers may need to assign a function reference to the .onclick property, and the else clause tries to make sure it doesn't overwrite a previous assignment.

    The showPage() function is the event listener that is called when a user clicks on one of the links. In DOM2-compliant browsers it's called with an Event object as the argument, but Internet Explorer uses a global window.event object instead, which doesn't have the same properties as the DOM2 one, hence the extra logic.

    The last line simply calls Links.init() to set up everything.

    The whole shebang is enclosed in an anonymous function, to avoid polluting the global namespace with unnecessary fluff:
    Code:
    (function () {...})();
    HTH
    Birnam wood is come to Dunsinane


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •