views:

221

answers:

2

I have a hierarchy of tags within my HTML which all contain onclick event handlers. The onclick is pushed onto the event stack from the leaf back through the root of the hierarchy. I only want to respond to the leaf onclick event. Can I flush the event stack rather than using a flag?

For instance...

    <ul>
      <li onclick="nada('1');"><a href="#1">1</a></li>
      <li onclick="nada('2');"><a href="#2">2</a>
        <ul>
          <li onclick="nada('2.1');"><a href="#2.1">2.1</a></li>
          <li onclick="nada('2.2');"><a href="#2.2">2.2</a></li>
          <li onclick="nada('2.3');"><a href="#2.3">2.3</a></li>
        </ul>
      </li>
      <li onclick="nada('4');"><a href="#4">4</a></li>
      <li onclick="nada('5');"><a href="#5">5</a></li>
    </ul>

Clicking on 2.2 using this function...

function nada(which)
  {
  alert(which);
  }

...will result in two alerts for '2.2' and '2'.

What could I add to the nada function to eliminate the alert for '2'?

A: 

I think this article on QuirksMode can help you: Javascript - Event order

Loris
+1  A: 

To stop the event bubbling up to parent elements you have to tell the event object about it. In IE, you set event.cancelBubble= true. In other browsers, you call event.stopPropagation().

You probably also want to turn off the default link-following action so that the browser doesn't keep jumping up to the top trying to follow the non-existing anchor links like #1. In IE, you set event.returnValue= false. In other browsers, you call event.preventDefault().

The event object is accessible as window.event on IE. On other browsers, it is passed into the event handler function. A way to pass the event into a function that works on both is:

      <li onclick="nada('2.1', event);"><a href="#2.1">2.1</a></li>

function nada(n, event) {
    alert(n);
    if ('stopPropagation' in event) {
        event.stopPropagation();
        event.preventDefault();
    } else {
        event.cancelBubble= true;
        event.returnValue= false;
    }
}

However it would probably be better all round to put the onclick event on the a element which it usually belongs. This helps for accessibility, as the a element will be focusable and keyboard-operable. And it means you don't have to worry about parents' click handlers being called.

(You can style the a to look like a plain block, if you want.)

You can then also kick out the redundant onclick links with a bit of unobtrusive scripting:

<ul id="nadalist">
  <li><a href="#1">1</a></li>
  <li><a href="#2">2</a>
      <ul>
          <li><a href="#2.1">2.1</a></li>
          <li><a href="#2.2">2.2</a></li>
          <li><a href="#2.3">2.3</a></li>
      </ul>
  </li>
  <li><a href="#4">4</a></li>
  <li><a href="#5">5</a></li>
</ul>

<script type="text/javascript">
    var links= document.getElementById('nadalist').getElementsByTagName('a');
    for (var i= links.length; i-->0;) {
        links[i].onclick= function() {
            alert(this.hash.substring(1));
            return false;
        }
    }
</script>
bobince
Thank you... event.stopPropagation(); ...was the key.
dacracot