Featured post

Closures, Lexical Scoping And Scope chain In JavaScript

Closures...You have heard a lot, or might have tried to study from different sources, but failed to get the point. Well to under...

Showing posts with label Event Capturing. Show all posts
Showing posts with label Event Capturing. Show all posts

Wednesday, 24 February 2016

Event Handling in JavaScript (Part 2)


We have already covered some basics of Event Handling in Part 1. We have seen how we can register events on objects like window, document or any document elements objects. Before moving further I will recommend you to read that first. This time we will explore Event Handler Invocation process.

Event Handler Invocation:


Once you have registered event handlers, web browser will automatically invoke it when event of specified type occur on specified object. In this section we will cover arguments on event handler, event handler context, event handler scope, return value of event handler, invocation order and last but not the least event propagation and cancellation. This will surely give you better understanding on Event Handling.

Event Handler Argument

Event Handlers are mostly invoked with an event object as their argument. By mostly I mean IE8 and below versions of IE (as usual :/ ) do not pass any object in argument. Instead event object is available through the global variable window.event.
For compatibility we can write our handler function as:

var handler = function(event) {
      event = event || window.event;
}

This || says that if event is undefined (i.e. not passed as argument) then refer to the window.event variable.
The property of the event object provide details about the event. The type property of event object specifies the type of the event that has occured.

Event Handler Context

As we know there are 4 different ways in which function can be invoked. All those ways differ in setting the context/this of the function. Before moving further I recommend you to read this post first for more information on context/this.
By now, I hope you know method invocation and function invocation. We will need that knowledge to understand event handler context.

When you register your event handler by setting a property of element like this:
e.onlick = function() {.....};
then event handlers are invoked as method invocation since element is an object and we are defining property of an object. In this case our context/this refers to the event target on which handler is registered and invoked.

e.onclick = function() {
      console.log(this);      // It will display element on which click event is fired.
}

Even when handler is registered using addEventListener() then also the context/this will be set to event target i.e. element on which event is fired or registered. Unfortunately, it is not true with attachEvent() method. Handlers regisered through with attachEvent() are invoked as functions and sets this/context to global (Window) object. But we can have workaround for this.

function addEvent(target, type, handler) {
      if (target.addEventListener) {
            target.addEventListener(type, handler, false)
      } else {
            target.attachEvent("on" + type, function(event) {
                  return handler.call(target, event);
            });
      }
}
But event handler using this method can nto be removed because second parameter (handler function for attachEvent()) is ananymous and is not retained anywhere to be passed in detachEvent().

Event Handler Scope

We have seen that JavaScript, like Python, is lexically scoped means function able to access the scope chain where it has been defined and not where it has been called. For more clear understanding on scope in JavaScript, follow this post.
So like all the other JavaScript functions, event handlers are also lexically scoped. They are executed in the scope in which they are defined and not the scope from which they are invoked.

However there will always be an weird case since we are talking about JavaScript. Event Handlers which are registered as HTML attributes have access to global variables but not to any local variables. But, for some reasons, they have access to modified scope chain. Event Handlers defined by HTML element have access to element's attribute, the containing form object and the document object as well, as if they are local variables to the handler function.

Handler Return Value

Somethimes, when return value of handler function is set to false then browser does not perform the default action. Means??? Suppose you have submitted a form whose handler is registerd via setting HTML attribute or by setting an object property, and if handler returns false then form will not get submitted. You can write client side validation in handler function.
Another use of returning false could be in onkeypress event's handler function. Check if pressed key is valid or not and return false if not valid (can be used when validation input email or etc.).

But one important point here to notice is, return value false will only work if handler is registered by setting HTML attribute or by object property. It won't work if handlers are registered through addEventListener() or attachEvent() methods. To prevent default actions from handler function registered through these two methods, you must have to call the preventDefault() method or set the returnValue property of the event object. (preventDefault() for addEventListener() and returnValue = false for attachEvent()).

Invocation Order

There might be more than one event handler functon registered on single HTML element or object. When an appropriate event occurs, browser must have to prioritize between the event handler funciton's execution sequence. Browser follows following order to execute a handler funciton in sequence:
  • Handlers registered by setting an object property or HTML attribute will be invoked first.
  • Handlers registered with addEventListener() will be invoked in order they were registered.
  • Handlers registered with attachEvent() can be invoked in any order and you should not be dependent on sequence of this order.

Event Propagation

Whenever an event occurs on Window object, browser executes the handler function of respective event. But for other event targets like document object or any other html element, story is little different. After executing Event Handler function, event bubbles up to the document hierarchy level. Now handler function of upper level element will execute, and this goes on until it reaches to Window Object. (Exception Events which do not bubble up: focus, blur and scroll events.) This Event Bubbling is actually third phase of Event Propagation process. Executing Event Handler function is itself actually second phase. You ask what is first phase? Remember the third Boolean parameter on addEventListener() function? Well, if passed true in that parameter, event handler is registered as an capturing event handler. What difference does capturing event handler function makes? If function registered as capturing Event Handler, the top most hierarchy function will execute first (i.e., handler of Window Object),then its child and this goes on until immediate parent of event target on which event has actually occurred. And main point is it will never execute handler function of event target on which event has actually occurred. (Basically event event Capturing is opposite process of Event Bubbling). Event Capturing is mostly used for debugging purposes.

Event Cancellation

To cancel event propagation, use stopPropagation() method on handlers registered through addEventListener(). IE9 or before does not support stopPropagation(), instead, the IE event object has a property cancelBubble. Set this property to true to prevent any further propagation. There is another method named stopImmediatePropagation(). Like stopPropagation(), this method prevents the propagation of events to any other objects. But it also prevents the invocation of any other event handlers registered on the same object.

Drop comments for any doubts.

Thursday, 11 February 2016

Event Handling in JavaScript (Part 1)


In this post I will cover some basic fundamentals of Event Handling and what are the different techniques of registering events.

Client side JavaScript program use an asynchronous event-driven programming model. If anything interesting happens to a document or window or element, browser generates an event for it. That event gets registered in event loop. Browser then fires event handler function for topmost event from event loop.

Lets understand above process in simple words. Event is something which is fired when user interacts with browser. Event can be click on button, hover on link, scroll on window, load of document, etc. If you want to perform any particular task on any event then you can write a function for that event. That function will be termed as Event Handler or Event Listener for that event.
If you fire lot of events back to back then browser will register all those event in a queue and will execute their event handler function one by one. That queue is called as Event Loop. Since JavaScript does not support multi tasking, those event handler functions will execute one after another.
Event Type is a string that specifies what kind of event occurred. Type "mousemove" signifies movement of mouse, "keydown" means key on the keyboard is pressed down and etc. Event Type sometimes called as Event Name.
Event Target is an object on which event has occurred or with which event is associated. Load event on Window, load event on document, click event on button etc. Some common event targets are Window, document or html element objects.
Event Object is an object that is associated with particular event and contains details about the event. Event Objects are passed as an argument to the event handler function. All event Objects have a type and target property. Type property specifies the event type and target property specifies Event target. (In IE8 or before use srcElement instead of target).
Event Propagation is process in which browser identifies objects on which event handler function should be triggered upon. Event Propagation is mostly confused as synonym of Event Bubbling but Event Propagation is much wider concept.
Event Propagation also includes the concept of Event Capturing which is opposite to Event Bubbling.


Event Bubbling and Event Capturing:
Suppose click event has occurred on anchor tag, browser will execute handler for that event. Now event will bubble up to the enclosing element of anchor tag maybe <p> tag, now handler for <p> tag will be executed. Again event will bubble up to the enclosing element of <p> tag, that could be <div> tag. Handler for <div> tag will now get executed. This process is event bubbling.
Event Capturing is opposite process of event bubbling. First handler for highest hierarchy element will get executed, then bubbles down to child element and this process goes on until it reaches to the parent of the element on which event has occurred initially. Interesting part is handler function of element on which originally event has occurred will not get executed.
Event capturing provides an opportunity to peek at events before they are delivered to their targets. A capturing event handler can be used for debugging.

Registering Event Handlers


You can register JavaScript Event Handlers in two different ways, set a property on the object or document element that is the event target or pass the handler to a method of the object or element. There are two versions of each technique.

 

Setting Event Handler Properties:

Easiest way to register an event handler function is by setting the Event name property of Event target to the desired event handler function.

Event target properties have name that consists of "on" prefix like, onmouseover, onclick, onhover etc. Event targets as earlier mentioned can be window, document etc.

window.onload = function() {
   
      // Look up an div tag with id header
      var header = document.getElementById("header");
      console.log(header);      // Printing element
}

This technique works for all kinds of browsers but it has some shortcomings. It won't allow you to register more than one type of event handler function for any event on particular event target. Means?? You can register only one event handler function for onload event on window object. If you are writing a library just go for addEventListener() method (Will explain this technique later in the post).

 

Setting Event Handler Attributes:

Another popular way of registering event is by setting attribute on corresponding HTML tag. Like:

<button type="submit" id="ironman" onclick="alert(I am IronMan!);">Identify</button>
<button type="submit" id="spiderman" onclick="greatPower()">Famous Dialog</button>
<script>
      var greatPower = function() {
            alert("Power is directly proportional to Responsibility. :p");
      }
</script>

There are lot of things to remember in order to use this technique.
  • Attribute value should always be JavaScript String
  • If there are multiple statements in attribute value then separate them with semicolon ;
  • Last thing to remember, you are mixing JavaScript code with HTML content. Some programmers avoid this technique in order to keep their code clean

 

addEventListener():

Here comes the technique which I will suggest you to use. This technique is supported by all the browsers other than IE8 and below. All Objects like window, document and other document elements has addEventListener method defined. This method takes three parameters, first: event name (prefix "on" is not used in the name of the event), second: event handler function, third: a Boolean value determining whether the event registered as an capturing event or not. You are wondering about the third parameter. Right? If passed true, event will registered as an capturing event else not. Basically capturing handlers of the window object are invoked first, then the capturing handlers of the document object, then the body object, and so on down the DOM tree until the capturing event handlers of the parent of the event target are invoked. Capturing event handlers registered on the event target itself are not invoked.

<button id="myButton" type="submit" value="submit">Submit</button>
<script>
      var b = document.getElementById("myButton");

       var clickHandler = function() {
             alert("Please do not block ads on this blog.");
      }
 
      b.addEventListener("click", clickHandler, false);

</script>

addEventListener() is paired with removeEventListener() method that expects the same three arguments but removes the event handler function from the object rather than adding it.

 

attachEvent():

Internet prior to IE9 does not support addEventListener() or removeEventListener(). Instead it uses attachEvent() or detachEvent() methods. There are some minor differences between these two method's implementation. 

Internet Explorer does not support Event Capturing, therefore there is no third parameter required in attachEvent() and detachEvent().
Unlike addEventListener(), attachEvent() takes prefix "on" in event name.
attachEvent() allows same event handler function to be registered more than once, allowing registered function to be invoked as many times as it was registered.

<button id="myButton" type="submit" value="submit">Submit</button>
<script>
      var b = document.getElementById("myButton");

       var clickHandler = function() {
             alert("Please do not block ads on this blog.");
      }

       if(window.addEventListener) {
              b.addEventListener("click", clickHandler, false);
        } else if(window.attachEvent) {
               b.attachEvent("onclick", clickHandler);
       }
</script>

Above code will ensure that if browser supports addEventListener() than it will use that method only else it will go attachEvent method. This practice makes your application backward browser compatible.

In next post we will explore the Event Handler Invocation process..