Event Capture and Bubbling

The DOM has two ways for objects to detect events: from the top down, and from the bottom up. The first method is known as event capture, the second is called event bubbling.

Event Capture

diagram showing arrows moving downwards

Let’s say that your document contains a<div>which contains a<p>which contains an<img>. Further, let’s say you’ve added an event listener to all of them. When a user clicks on the image, amouseclickevent occurs.

Even though the user clicked the image, the image doesn’t get the event first. Instead, the event listener attached to the document grabs the event first and processes it. (That is, it captures the event before it gets to its intended target.) The event is then passed down to the <div>’s event listener. The event then goes to the <p>, and finally to the <img>. That is, all of the clicked-on object’s “ancestors” higher up in the document capture the event for processing before sending it down the chain to its intended target. You can try event capture in a pop-up window. (This only works in Mozilla.)

Event Bubbling

diagram showing arrows moving upwards

Now let’s look at the same situation from the inside out. You have an <img>inside a <p>, which is inside a <div>, which is inside your document. When a user clicks the image, this time the events rise like a bubble in a glass of water. The click’s original target, the <img>, gets to see the event first, and then passes it upwards to the <p>for further processing, which passes it on to the <div>, which finally passes it up to the document. You can try event bubbling in a pop-up window. (This only works in Mozilla.)

Here are the relevant parts of the source code for both demos.

Event Capture and Bubbling

The DOM has two ways for objects to detect events: from the top down, and from the bottom up. The first method is known as event capture, the second is called event bubbling.

Event Capture

diagram showing arrows moving downwards

Let’s say that your document contains a<div>which contains a<p>which contains an<img>. Further, let’s say you’ve added an event listener to all of them. When a user clicks on the image, amouseclickevent occurs.

Even though the user clicked the image, the image doesn’t get the event first. Instead, the event listener attached to the document grabs the event first and processes it. (That is, it captures the event before it gets to its intended target.) The event is then passed down to the <div>’s event listener. The event then goes to the <p>, and finally to the <img>. That is, all of the clicked-on object’s “ancestors” higher up in the document capture the event for processing before sending it down the chain to its intended target. You can try event capture in a pop-up window. (This only works in Mozilla.)

Event Bubbling

diagram showing arrows moving upwards

Now let’s look at the same situation from the inside out. You have an <img>inside a <p>, which is inside a <div>, which is inside your document. When a user clicks the image, this time the events rise like a bubble in a glass of water. The click’s original target, the <img>, gets to see the event first, and then passes it upwards to the <p>for further processing, which passes it on to the <div>, which finally passes it up to the document. You can try event bubbling in a pop-up window. (This only works in Mozilla.)

Here are the relevant parts of the source code for both demos.

http://www.tapper-ware.net/blog/?p=11

에서 참조

Object Oriented Programming and Event Handlers

When I started writing Object Oriented Javascript, there was one major pitfall: Event handlers. Event handlers are functions that are launched when a certain event occurs inside the browser, say a click on an image.

Most people are familar with the onclick, onload (…) attributes in HTML and a few selected ones even know how to work with addEventListener and attachEvent (see below), but no matter what system you use, there’s one thing that never works and that’s using event handlers in an object oriented application.

Why? Well, for some reason (I wish I knew which one), both the W3C, which is the consortium for web standards and Microsoft (which is a company against standards, but they usually behave the same way) defined event listeners to take exactly one parameter, and that’s the function which is supposed to be called when an event occurs.

Time for sample code. Imagine you have three buttons and want each one to display its number when you click on it. And imagine you don’t want to do this manually, because there could be as many as 1000 buttons. Here’s the HTML part:

<html>

 <head>

  <title>HelloButton</title>

  <script></script>

 </head>

 <body>

 </body>

</html>

OK, now let’s define our “Button” class. A class is nothing more than a blueprint which you can lateron use to create objects that are all constructed according to this blueprint… In Javascript they are really easy to make, you just create a constructor function and that’s pretty much it. The only differences to a normal function are that:

a) A constructor can’t return anything, because it always returns the object it created.

b) You can use “this” to set properties of that object (object, not class: each object has its own properties, for example two objects of the class “person” might have a property “name”. For person1, this could be “Hans”, for person2 “Peter”).

So, to define a button class with a property “buttonTitle” and a HTML element to display the button all we have to do is this:

function button(title){

 /* Create an input element and save a reference in the element property */

 this.element=document.createElement("input");

 /* Set the type of the HTML element to "button" */

 this.element.setAttribute("type","button");

 /* Set the label of the HTML element to title */

 this.element.setAttribute("value", title);

 /* Append that element to the HTML body */

 document.getElementsByTagName("body")[0].appendChild(this.element);

 /* Set the title property to the supplied title */

 this.title=title;

}

Nice, huh? OK, one more thing before we actually get to the event handlers. To define a function that can also use “this” (that’s called a method) we have to use a special notation…

classname.prototype.methodname=function(parameters){code}

Looks strange, I know. But it never really changes, so all you’ve got to do is copy paste. Let’s say we want to add a “showTitle” method that uses alert() to display this.title:

button.prototype.showTitle=function(){

 alert(this.title);

}

Not that hard, is it? OK, now we’ve got everything working, but we still have to actually create the objects using a simple “for” loop (we do this inside a “main” function which we specify for body.onload, because otherwise the code which tries to append something to the body might run before the body is actually there) , so now our whole document looks like this:

<html>

 <head>

  <title>HelloButton</title>

  <script>

function button(title){

 this.element=document.createElement("input");

 this.element.setAttribute("type","button");

 this.element.setAttribute("value", title);

 document.getElementsByTagName("body")[0].appendChild(this.element);

 this.title=title;

}



button.prototype.showTitle=function(){

 alert(this.title);

}



function main(){

 var buttonObjects=new Array();

  for(var i=0;i<3;i++){

   buttonObjects[i]=new button("Button #"+i);

  }

}

  </script>

 </head>

 <body onload="main()">

 </body>

</html>

So now we have the button class, the objects and the HTML buttons: Hurray! But nothing happens when we click them, because we haven’t defined any behaviour yet.

So let’s extend our constructor function (“function button(title)…”) a little. You can look at the previous post if you want to use proper eventListeners, but right now we’re going to just use the onclick attribute.

The seemingly logical thing would be to just add a line that sets the onclick attribute to this.showTitle, right?

this.element.onclick=this.showTitle;

Sadly, this doesn’t work… we don’t get this.title! Why? well, when an event handler gets executed, it gets executed in such a way that “this” means the element that sent the event, in the case the HTML “input” element, not our object.

So what do we do? Well, there’s a nasty little method that every function in Javascript has: this is the “call” method and it executes a function so that “this” means the first parameter. So what we want to do would be something like:

this.element.onclick=this.showTitle.call(this);

Looks nice I know, but sadly it still doesn’t work, because that line actually evaluates this.showTitle.call(this) and then sets this.element.onclick to the value it returned.

But if we wrap this inside yet another function, we’re at least getting closer: Now onclick is at least set to a function, eventhough it still doesn’t work, because “this” is still the HTML element.

this.element.onclick=function(){this.showTitle.call(this)};

The trick is now to actually create a function that we can somehow pass “this” to and which will then return a new function which has “this” hardcoded to the right value. The thing we need here is called Javascript closures and you can easily find documents that explain in 100 or more pages what it is and how it works… but we really only need to know how to use it.

First we create a new function outside any object. Let’s call it methodize. This function should take as a parameters a given function and a reference to “this”, we call this “scope”:

function methodize(methodize_func, methodize_scope){

}

As we said before methodize should return a function:

function methodize(methodize_func,methodize_scope){

    return (function(){});

}

And what should that function contain? Exactly. The nasty “this.showTitle.call(this)”, but because we designed this for any function, not just “this.showTitle” we use “methodize_func” instead and “methodize_scope” instead of “this”.

function methodize(methodize_func,methodize_scope){

    return (function(){methodize_func.call(methodize_scope);});

}

Now, when we run methodize we get a function that when executed calls the given method in the given scope. We can now asign that to onclick

this.element.onclick=methodize(this.showTitle,this);

And that’s it! Now we get the eventListener executed in the correct scope! I know it seems hard and unneccessary, but once you get used to it, it’s really just copy/paste. Here’s the full code again:

<html>

 <head>

  <title>HelloButton</title>

  <script>

function methodize(methodize_func,methodize_scope){

    return (function(){methodize_func.call(methodize_scope);});

}



function button(title){

 this.element=document.createElement("input");

 this.element.setAttribute("type","button");

 this.element.setAttribute("value", title);

 document.getElementsByTagName("body")[0].appendChild(this.element);

 this.title=title;

 this.element.onclick=methodize(this.showTitle,this);

}



button.prototype.showTitle=function(){

 alert(this.title);

}



function main(){

 var buttonObjects=new Array();

  for(var i=0;i<3;i++){

   buttonObjects[i]=new button("Button #"+i);

  }

}

  </script>

 </head>

 <body onload="main()">

 </body>

</html>

P.S:
There’s one thing that we could add to our methodize function and that’s passing of the event and any other parameters to the methodize_func.

It’s really not much of a deal

function methodize(methodize_func,methodize_scope){

    /* Copy the arguments array, which contains all parameters

       to  methodize_args, except entries #0 and #1  (methodize_func

       ,methodize_scope) */

    var methodize_args=new Array();

    for(var i=2;i<arguments.length;i++) methodize_args.push(arguments[i]);

    /* Return a function that takes an event parameter itself

       and passes it on to methodize_func, along with methodize_args */

    return (function(evt){methodize_func.call(methodize_scope,evt,methodize_args);});

}

And voilà: Suddently our target function runs not only in the correct scope, but it also receives the event that triggered its execution as first parameter and whatever you specified after methodize_scope as an array.

http://www.tapper-ware.net/blog/?p=11

에서 참조

Object Oriented Programming and Event Handlers

When I started writing Object Oriented Javascript, there was one major pitfall: Event handlers. Event handlers are functions that are launched when a certain event occurs inside the browser, say a click on an image.

Most people are familar with the onclick, onload (…) attributes in HTML and a few selected ones even know how to work with addEventListener and attachEvent (see below), but no matter what system you use, there’s one thing that never works and that’s using event handlers in an object oriented application.

Why? Well, for some reason (I wish I knew which one), both the W3C, which is the consortium for web standards and Microsoft (which is a company against standards, but they usually behave the same way) defined event listeners to take exactly one parameter, and that’s the function which is supposed to be called when an event occurs.

Time for sample code. Imagine you have three buttons and want each one to display its number when you click on it. And imagine you don’t want to do this manually, because there could be as many as 1000 buttons. Here’s the HTML part:

<html>

 <head>

  <title>HelloButton</title>

  <script></script>

 </head>

 <body>

 </body>

</html>

OK, now let’s define our “Button” class. A class is nothing more than a blueprint which you can lateron use to create objects that are all constructed according to this blueprint… In Javascript they are really easy to make, you just create a constructor function and that’s pretty much it. The only differences to a normal function are that:

a) A constructor can’t return anything, because it always returns the object it created.

b) You can use “this” to set properties of that object (object, not class: each object has its own properties, for example two objects of the class “person” might have a property “name”. For person1, this could be “Hans”, for person2 “Peter”).

So, to define a button class with a property “buttonTitle” and a HTML element to display the button all we have to do is this:

function button(title){

 /* Create an input element and save a reference in the element property */

 this.element=document.createElement("input");

 /* Set the type of the HTML element to "button" */

 this.element.setAttribute("type","button");

 /* Set the label of the HTML element to title */

 this.element.setAttribute("value", title);

 /* Append that element to the HTML body */

 document.getElementsByTagName("body")[0].appendChild(this.element);

 /* Set the title property to the supplied title */

 this.title=title;

}

Nice, huh? OK, one more thing before we actually get to the event handlers. To define a function that can also use “this” (that’s called a method) we have to use a special notation…

classname.prototype.methodname=function(parameters){code}

Looks strange, I know. But it never really changes, so all you’ve got to do is copy paste. Let’s say we want to add a “showTitle” method that uses alert() to display this.title:

button.prototype.showTitle=function(){

 alert(this.title);

}

Not that hard, is it? OK, now we’ve got everything working, but we still have to actually create the objects using a simple “for” loop (we do this inside a “main” function which we specify for body.onload, because otherwise the code which tries to append something to the body might run before the body is actually there) , so now our whole document looks like this:

<html>

 <head>

  <title>HelloButton</title>

  <script>

function button(title){

 this.element=document.createElement("input");

 this.element.setAttribute("type","button");

 this.element.setAttribute("value", title);

 document.getElementsByTagName("body")[0].appendChild(this.element);

 this.title=title;

}



button.prototype.showTitle=function(){

 alert(this.title);

}



function main(){

 var buttonObjects=new Array();

  for(var i=0;i<3;i++){

   buttonObjects[i]=new button("Button #"+i);

  }

}

  </script>

 </head>

 <body onload="main()">

 </body>

</html>

So now we have the button class, the objects and the HTML buttons: Hurray! But nothing happens when we click them, because we haven’t defined any behaviour yet.

So let’s extend our constructor function (“function button(title)…”) a little. You can look at the previous post if you want to use proper eventListeners, but right now we’re going to just use the onclick attribute.

The seemingly logical thing would be to just add a line that sets the onclick attribute to this.showTitle, right?

this.element.onclick=this.showTitle;

Sadly, this doesn’t work… we don’t get this.title! Why? well, when an event handler gets executed, it gets executed in such a way that “this” means the element that sent the event, in the case the HTML “input” element, not our object.

So what do we do? Well, there’s a nasty little method that every function in Javascript has: this is the “call” method and it executes a function so that “this” means the first parameter. So what we want to do would be something like:

this.element.onclick=this.showTitle.call(this);

Looks nice I know, but sadly it still doesn’t work, because that line actually evaluates this.showTitle.call(this) and then sets this.element.onclick to the value it returned.

But if we wrap this inside yet another function, we’re at least getting closer: Now onclick is at least set to a function, eventhough it still doesn’t work, because “this” is still the HTML element.

this.element.onclick=function(){this.showTitle.call(this)};

The trick is now to actually create a function that we can somehow pass “this” to and which will then return a new function which has “this” hardcoded to the right value. The thing we need here is called Javascript closures and you can easily find documents that explain in 100 or more pages what it is and how it works… but we really only need to know how to use it.

First we create a new function outside any object. Let’s call it methodize. This function should take as a parameters a given function and a reference to “this”, we call this “scope”:

function methodize(methodize_func, methodize_scope){

}

As we said before methodize should return a function:

function methodize(methodize_func,methodize_scope){

    return (function(){});

}

And what should that function contain? Exactly. The nasty “this.showTitle.call(this)”, but because we designed this for any function, not just “this.showTitle” we use “methodize_func” instead and “methodize_scope” instead of “this”.

function methodize(methodize_func,methodize_scope){

    return (function(){methodize_func.call(methodize_scope);});

}

Now, when we run methodize we get a function that when executed calls the given method in the given scope. We can now asign that to onclick

this.element.onclick=methodize(this.showTitle,this);

And that’s it! Now we get the eventListener executed in the correct scope! I know it seems hard and unneccessary, but once you get used to it, it’s really just copy/paste. Here’s the full code again:

<html>

 <head>

  <title>HelloButton</title>

  <script>

function methodize(methodize_func,methodize_scope){

    return (function(){methodize_func.call(methodize_scope);});

}



function button(title){

 this.element=document.createElement("input");

 this.element.setAttribute("type","button");

 this.element.setAttribute("value", title);

 document.getElementsByTagName("body")[0].appendChild(this.element);

 this.title=title;

 this.element.onclick=methodize(this.showTitle,this);

}



button.prototype.showTitle=function(){

 alert(this.title);

}



function main(){

 var buttonObjects=new Array();

  for(var i=0;i<3;i++){

   buttonObjects[i]=new button("Button #"+i);

  }

}

  </script>

 </head>

 <body onload="main()">

 </body>

</html>

P.S:
There’s one thing that we could add to our methodize function and that’s passing of the event and any other parameters to the methodize_func.

It’s really not much of a deal

function methodize(methodize_func,methodize_scope){

    /* Copy the arguments array, which contains all parameters

       to  methodize_args, except entries #0 and #1  (methodize_func

       ,methodize_scope) */

    var methodize_args=new Array();

    for(var i=2;i<arguments.length;i++) methodize_args.push(arguments[i]);

    /* Return a function that takes an event parameter itself

       and passes it on to methodize_func, along with methodize_args */

    return (function(evt){methodize_func.call(methodize_scope,evt,methodize_args);});

}

And voilà: Suddently our target function runs not only in the correct scope, but it also receives the event that triggered its execution as first parameter and whatever you specified after methodize_scope as an array.

http://www.tapper-ware.net/blog/?p=11

에서 참조

Object Oriented Programming and Event Handlers

When I started writing Object Oriented Javascript, there was one major pitfall: Event handlers. Event handlers are functions that are launched when a certain event occurs inside the browser, say a click on an image.

Most people are familar with the onclick, onload (…) attributes in HTML and a few selected ones even know how to work with addEventListener and attachEvent (see below), but no matter what system you use, there’s one thing that never works and that’s using event handlers in an object oriented application.

Why? Well, for some reason (I wish I knew which one), both the W3C, which is the consortium for web standards and Microsoft (which is a company against standards, but they usually behave the same way) defined event listeners to take exactly one parameter, and that’s the function which is supposed to be called when an event occurs.

Time for sample code. Imagine you have three buttons and want each one to display its number when you click on it. And imagine you don’t want to do this manually, because there could be as many as 1000 buttons. Here’s the HTML part:

<html>

 <head>

  <title>HelloButton</title>

  <script></script>

 </head>

 <body>

 </body>

</html>

OK, now let’s define our “Button” class. A class is nothing more than a blueprint which you can lateron use to create objects that are all constructed according to this blueprint… In Javascript they are really easy to make, you just create a constructor function and that’s pretty much it. The only differences to a normal function are that:

a) A constructor can’t return anything, because it always returns the object it created.

b) You can use “this” to set properties of that object (object, not class: each object has its own properties, for example two objects of the class “person” might have a property “name”. For person1, this could be “Hans”, for person2 “Peter”).

So, to define a button class with a property “buttonTitle” and a HTML element to display the button all we have to do is this:

function button(title){

 /* Create an input element and save a reference in the element property */

 this.element=document.createElement("input");

 /* Set the type of the HTML element to "button" */

 this.element.setAttribute("type","button");

 /* Set the label of the HTML element to title */

 this.element.setAttribute("value", title);

 /* Append that element to the HTML body */

 document.getElementsByTagName("body")[0].appendChild(this.element);

 /* Set the title property to the supplied title */

 this.title=title;

}

Nice, huh? OK, one more thing before we actually get to the event handlers. To define a function that can also use “this” (that’s called a method) we have to use a special notation…

classname.prototype.methodname=function(parameters){code}

Looks strange, I know. But it never really changes, so all you’ve got to do is copy paste. Let’s say we want to add a “showTitle” method that uses alert() to display this.title:

button.prototype.showTitle=function(){

 alert(this.title);

}

Not that hard, is it? OK, now we’ve got everything working, but we still have to actually create the objects using a simple “for” loop (we do this inside a “main” function which we specify for body.onload, because otherwise the code which tries to append something to the body might run before the body is actually there) , so now our whole document looks like this:

<html>

 <head>

  <title>HelloButton</title>

  <script>

function button(title){

 this.element=document.createElement("input");

 this.element.setAttribute("type","button");

 this.element.setAttribute("value", title);

 document.getElementsByTagName("body")[0].appendChild(this.element);

 this.title=title;

}



button.prototype.showTitle=function(){

 alert(this.title);

}



function main(){

 var buttonObjects=new Array();

  for(var i=0;i<3;i++){

   buttonObjects[i]=new button("Button #"+i);

  }

}

  </script>

 </head>

 <body onload="main()">

 </body>

</html>

So now we have the button class, the objects and the HTML buttons: Hurray! But nothing happens when we click them, because we haven’t defined any behaviour yet.

So let’s extend our constructor function (“function button(title)…”) a little. You can look at the previous post if you want to use proper eventListeners, but right now we’re going to just use the onclick attribute.

The seemingly logical thing would be to just add a line that sets the onclick attribute to this.showTitle, right?

this.element.onclick=this.showTitle;

Sadly, this doesn’t work… we don’t get this.title! Why? well, when an event handler gets executed, it gets executed in such a way that “this” means the element that sent the event, in the case the HTML “input” element, not our object.

So what do we do? Well, there’s a nasty little method that every function in Javascript has: this is the “call” method and it executes a function so that “this” means the first parameter. So what we want to do would be something like:

this.element.onclick=this.showTitle.call(this);

Looks nice I know, but sadly it still doesn’t work, because that line actually evaluates this.showTitle.call(this) and then sets this.element.onclick to the value it returned.

But if we wrap this inside yet another function, we’re at least getting closer: Now onclick is at least set to a function, eventhough it still doesn’t work, because “this” is still the HTML element.

this.element.onclick=function(){this.showTitle.call(this)};

The trick is now to actually create a function that we can somehow pass “this” to and which will then return a new function which has “this” hardcoded to the right value. The thing we need here is called Javascript closures and you can easily find documents that explain in 100 or more pages what it is and how it works… but we really only need to know how to use it.

First we create a new function outside any object. Let’s call it methodize. This function should take as a parameters a given function and a reference to “this”, we call this “scope”:

function methodize(methodize_func, methodize_scope){

}

As we said before methodize should return a function:

function methodize(methodize_func,methodize_scope){

    return (function(){});

}

And what should that function contain? Exactly. The nasty “this.showTitle.call(this)”, but because we designed this for any function, not just “this.showTitle” we use “methodize_func” instead and “methodize_scope” instead of “this”.

function methodize(methodize_func,methodize_scope){

    return (function(){methodize_func.call(methodize_scope);});

}

Now, when we run methodize we get a function that when executed calls the given method in the given scope. We can now asign that to onclick

this.element.onclick=methodize(this.showTitle,this);

And that’s it! Now we get the eventListener executed in the correct scope! I know it seems hard and unneccessary, but once you get used to it, it’s really just copy/paste. Here’s the full code again:

<html>

 <head>

  <title>HelloButton</title>

  <script>

function methodize(methodize_func,methodize_scope){

    return (function(){methodize_func.call(methodize_scope);});

}



function button(title){

 this.element=document.createElement("input");

 this.element.setAttribute("type","button");

 this.element.setAttribute("value", title);

 document.getElementsByTagName("body")[0].appendChild(this.element);

 this.title=title;

 this.element.onclick=methodize(this.showTitle,this);

}



button.prototype.showTitle=function(){

 alert(this.title);

}



function main(){

 var buttonObjects=new Array();

  for(var i=0;i<3;i++){

   buttonObjects[i]=new button("Button #"+i);

  }

}

  </script>

 </head>

 <body onload="main()">

 </body>

</html>

P.S:
There’s one thing that we could add to our methodize function and that’s passing of the event and any other parameters to the methodize_func.

It’s really not much of a deal

function methodize(methodize_func,methodize_scope){

    /* Copy the arguments array, which contains all parameters

       to  methodize_args, except entries #0 and #1  (methodize_func

       ,methodize_scope) */

    var methodize_args=new Array();

    for(var i=2;i<arguments.length;i++) methodize_args.push(arguments[i]);

    /* Return a function that takes an event parameter itself

       and passes it on to methodize_func, along with methodize_args */

    return (function(evt){methodize_func.call(methodize_scope,evt,methodize_args);});

}

And voilà: Suddently our target function runs not only in the correct scope, but it also receives the event that triggered its execution as first parameter and whatever you specified after methodize_scope as an array.

http://javascript.info/tutorial/bubbling-and-capturing

에서 참조

Bubbling and capturing

  1. Bubbling
    1. this and event.target
    2. Stopping the bubbling
  2. Capturing
  3. Summary

DOM elements can be nested inside each other. And somehow, the handler of the parent works even if you click on it’s child.

The reason is event bubbling.

For example, the following DIV handler runs even if you click a nested tag like EM or CODE:

<div onclick="alert('Div handler worked!')">
  <em>Click here triggers on nested <code>EM</code>, not on <code>DIV</code></em>
</div>

That’s because an event bubbles from the nested tag up and triggers the parent.

Bubbling

The main principle of bubbling states:
After an event triggers on the deepest possible element, it then triggers on parents in nesting order.

For example, there are 3 nested divs:

01 <!DOCTYPE HTML>
02 <html>
03 <body>
04 <link type="text/css" rel="stylesheet" href="example.css">
05 
06 <div class="d1">1  <!-- the topmost -->
07     <div class="d2">2
08         <div class="d3">3 <!-- the innermost -->
09         </div>
10     </div>
11 </div>
12 
13 </body>
14 </html>

The bubbling guarantees that click on Div 3 will trigger onclick first on the innermost element 3 (also caled the target), then on the element 2, and the last will be element 1.

Bubbling events order

The order is called a bubbling order, because an event bubbles from the innermost element up through parents, like a bubble of air in the water.

Click below to see it bubble:

Open the code in new window

this and event.target

The deepest element which triggered the event is called the target or, the originating element.

Internet Explorer has the srcElement property for it, all W3C-compliant browsers use event.target. The cross-browser code is usually like this:

var target = event.target || event.srcElement

When handlers trigger on parents:

  • event.target/srcElement – remains the same originating element.
  • this – is the current element, the one event has bubbled to, the one which runs the handler.

Bubbling events order

In the example below, each DIV has an onclick handler which outputs both target and this.

Click on a div.

Note that:

  • the target is constant through all bubbling process,
  • this changes and gets highlighted.

Open the code in new window

In W3C-compliant browsers this is also available as event.currentTarget.

attachEvent does not pass this or event.currentTarget at all.

Stopping the bubbling

The bubbling goes right to the top. When an event occurs on an element – it will bubble up to <HTML>, triggering handlers on it’s way.

But a handler may decide that event is fully processed and stop the bubbling.

The code is:

  • For W3C-compliant browsers:
    event.stopPropagation()
  • For IE<9:
    event.cancelBubble = true

The cross-browser-code:

01 element.onclick = function(event) {
02     event = event || window.event // cross-browser event
03      
04     if (event.stopPropagation) {
05         // W3C standard variant
06         event.stopPropagation()
07     } else {
08         // IE variant
09         event.cancelBubble = true
10     }
11 }

There is a one-lined variant too:

event.stopPropagation ? event.stopPropagation() : (event.cancelBubble=true)

If the element has several handlers on same event, then handlers are independent. All of them get executed..

For example, if there are two onclick handlers on the same link, then stopping bubbling in one of them has no effect on the other one. Also, the browser doesn’t guarantee the order in which they trigger.

Capturing

In all browsers, except IE<9, there are two stages of event processing.

The event first goes down – that’s called capturing, and then bubbles up. This behavior is standartized in W3C specification.

W3C events order

According to this model, the event:

  1. Captures down – through 1 -> 2 -> 3.
  2. Bubbles up – through 3 -> 2 -> 1.

All methods of event handling ignore the caputiring phase. Using addEventListener with last argument true is only the way to catch the event at capturing.

elem.addEventListener( type, handler, phase )

phase = true The handler is set on the capturing phase. phase = falseThe handler is set on the bubbling phase.

Click in a div below to see capturing in action (no IE<9):

It should be 1 -> 2 -> 3.

Source JavaScript of the example:

1 var divs = document.getElementsByTagName('div')
2 
3 for(var i=0; i<divs.length; i++) {
4   divs[i].addEventListener("click", highlightThis, true)
5 }

Click to open in the playground: tutorial/browser/events/bubbling/capture/index.html.

In real-life the capturing phase is rarely used. But..
There are events which don’t bubble, but can be captured. For example, onfocus/onblur.

Now let’s assign handlers at both stages.

Click on a div below to see the event processing order (no IE<9):

It should be 1 -> 2 -> 3 -> 3 -> 2 -> 1.

Source JavaScript of the example:

1 var divs = document.getElementsByTagName('div')
2 
3 for(var i=0; i<divs.length; i++) {
4   divs[i].addEventListener("click", highlightThis, true)
5   divs[i].addEventListener("click", highlightThis, false)
6 }

Click to open in the playground: tutorial/browser/events/bubbling/both/index.html.

Summary

  • Events first are captured down to deepest target, then bubble up. In IE<9 they only bubble.
  • All handlers work on bubbling stage excepts addEventListener with last argument true, which is the only way to catch the event on capturing stage.
  • Bubbling/capturing can be stopped by event.cancelBubble=true (IE) or event.stopPropagation() for other browsers.

http://javascript.info/tutorial/bubbling-and-capturing

에서 참조

Bubbling and capturing

  1. Bubbling
    1. this and event.target
    2. Stopping the bubbling
  2. Capturing
  3. Summary

DOM elements can be nested inside each other. And somehow, the handler of the parent works even if you click on it’s child.

The reason is event bubbling.

For example, the following DIV handler runs even if you click a nested tag like EM or CODE:

<div onclick="alert('Div handler worked!')">
  <em>Click here triggers on nested <code>EM</code>, not on <code>DIV</code></em>
</div>

That’s because an event bubbles from the nested tag up and triggers the parent.

Bubbling

The main principle of bubbling states:
After an event triggers on the deepest possible element, it then triggers on parents in nesting order.

For example, there are 3 nested divs:

01 <!DOCTYPE HTML>
02 <html>
03 <body>
04 <link type="text/css" rel="stylesheet" href="example.css">
05 
06 <div class="d1">1  <!-- the topmost -->
07     <div class="d2">2
08         <div class="d3">3 <!-- the innermost -->
09         </div>
10     </div>
11 </div>
12 
13 </body>
14 </html>

The bubbling guarantees that click on Div 3 will trigger onclick first on the innermost element 3 (also caled the target), then on the element 2, and the last will be element 1.

Bubbling events order

The order is called a bubbling order, because an event bubbles from the innermost element up through parents, like a bubble of air in the water.

Click below to see it bubble:

Open the code in new window

this and event.target

The deepest element which triggered the event is called the target or, the originating element.

Internet Explorer has the srcElement property for it, all W3C-compliant browsers use event.target. The cross-browser code is usually like this:

var target = event.target || event.srcElement

When handlers trigger on parents:

  • event.target/srcElement – remains the same originating element.
  • this – is the current element, the one event has bubbled to, the one which runs the handler.

Bubbling events order

In the example below, each DIV has an onclick handler which outputs both target and this.

Click on a div.

Note that:

  • the target is constant through all bubbling process,
  • this changes and gets highlighted.

Open the code in new window

In W3C-compliant browsers this is also available as event.currentTarget.

attachEvent does not pass this or event.currentTarget at all.

Stopping the bubbling

The bubbling goes right to the top. When an event occurs on an element – it will bubble up to <HTML>, triggering handlers on it’s way.

But a handler may decide that event is fully processed and stop the bubbling.

The code is:

  • For W3C-compliant browsers:
    event.stopPropagation()
  • For IE<9:
    event.cancelBubble = true

The cross-browser-code:

01 element.onclick = function(event) {
02     event = event || window.event // cross-browser event
03      
04     if (event.stopPropagation) {
05         // W3C standard variant
06         event.stopPropagation()
07     } else {
08         // IE variant
09         event.cancelBubble = true
10     }
11 }

There is a one-lined variant too:

event.stopPropagation ? event.stopPropagation() : (event.cancelBubble=true)

If the element has several handlers on same event, then handlers are independent. All of them get executed..

For example, if there are two onclick handlers on the same link, then stopping bubbling in one of them has no effect on the other one. Also, the browser doesn’t guarantee the order in which they trigger.

Capturing

In all browsers, except IE<9, there are two stages of event processing.

The event first goes down – that’s called capturing, and then bubbles up. This behavior is standartized in W3C specification.

W3C events order

According to this model, the event:

  1. Captures down – through 1 -> 2 -> 3.
  2. Bubbles up – through 3 -> 2 -> 1.

All methods of event handling ignore the caputiring phase. Using addEventListener with last argument true is only the way to catch the event at capturing.

elem.addEventListener( type, handler, phase )

phase = true The handler is set on the capturing phase. phase = falseThe handler is set on the bubbling phase.

Click in a div below to see capturing in action (no IE<9):

It should be 1 -> 2 -> 3.

Source JavaScript of the example:

1 var divs = document.getElementsByTagName('div')
2 
3 for(var i=0; i<divs.length; i++) {
4   divs[i].addEventListener("click", highlightThis, true)
5 }

Click to open in the playground: tutorial/browser/events/bubbling/capture/index.html.

In real-life the capturing phase is rarely used. But..
There are events which don’t bubble, but can be captured. For example, onfocus/onblur.

Now let’s assign handlers at both stages.

Click on a div below to see the event processing order (no IE<9):

It should be 1 -> 2 -> 3 -> 3 -> 2 -> 1.

Source JavaScript of the example:

1 var divs = document.getElementsByTagName('div')
2 
3 for(var i=0; i<divs.length; i++) {
4   divs[i].addEventListener("click", highlightThis, true)
5   divs[i].addEventListener("click", highlightThis, false)
6 }

Click to open in the playground: tutorial/browser/events/bubbling/both/index.html.

Summary

  • Events first are captured down to deepest target, then bubble up. In IE<9 they only bubble.
  • All handlers work on bubbling stage excepts addEventListener with last argument true, which is the only way to catch the event on capturing stage.
  • Bubbling/capturing can be stopped by event.cancelBubble=true (IE) or event.stopPropagation() for other browsers.