onclick=“” vs event handler

If I want a function to be executed, I prefer doing inline js:

<p id="element" onclick="doSomething();">Click me</p>

because it is easier to debug.

However, I hear people saying not to use inline js, and do:

document.getElementById('element').onclick = doSomething;

Why is the js event listener recommended?

Answers:

Answer

Basically it has to do with the whole keep everything separate I believe. So keep HTML/CSS/JS all separate. It makes your HTML tidier and, I think, easier to navigate without.

Then when/if you need to make large changes, you have ample space with having to shift the inline JS to an external file anyway OR if you want to apply the same function to more than one button, then it's less code. And less code is a happier place

If you have your JS files properly, and thoroughly documented then navigating them by an outside person is made eaiser

Answer

One big argument against inline event handlers, and the argument that is addressed by the other answers here is the separation of presentation and logic.

However, there is actually a bigger problem IMO: The somehow elusive way how inline event handlers are evaluated.

As you may know, the content of the on* attributes will be used as body of the event handler function. But what characteristics does this function have?

One of the surprising ones is that properties of some ancestor elements and of the element itself are in the scope of the inline event handler.

<form>
    <input name="foo" />
    <button type="button" onclick="console.log(foo); console.log(window.foo);">
        Click me
    </button>
    <div onclick="console.log(foo);">Click me as well!</div>
</form>

Clicking the button logs

<input name="foo"></input>
undefined

in the console. The fact that window.foo is undefined tells you that there is no global variable foo. So where does the variable foo come from? Why does console.log(foo) log the input element and not throw a reference error?
Because the properties of the form element are in the scope of the event handler and the form element has a property for each named form control element it contains. You can easily test this with console.log(document.querySelector('form').foo).

Now, clicking the div element actually throws a reference error:

ReferenceError: foo is not defined

So apparently the form element is only in scope of form control elements, not any descendant. How confusing is that?

Similarly, the properties of the document object are also in the scope of inline event handlers, which can lead to some surprising bugs (did you know that document has a property plugins?).

How exactly inline event handlers are evaluated is formalized in the HTML5 spec. Have a loop at step 10 in particular where he scope chain creation is described.


Conclusion:

Because of this implicit connection between elements and inline event handlers, bugs can be really hard to track. It's of course fine to use inline event handlers if you just want to test something. But using them in production code comes with a higher maintenance cost.

The articles at quirksmode.org explain the different ways of binding event handlers and their (dis)advantages very well.

Answer

There are a lot of reasons to avoid inline JavaScript and one of the perhaps most important is code maintainability.

A quick example (I am using jQuery simply for demonstration purposes).

<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>

What if suddenly you get a request to change all your paragraphs to execute another function? In your example you would have to change everything manually in your HTML code. However if you choose to separate HTML from JavaScript you could simply do it like this.

<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>

$('.element').bind('click', doSomethingElse);

The HTML code is also cleaner which allows the designers to focus exclusively on design without fear that they might actually break something while working on a project which also involves other people.

EDIT: Providing example for my comment bellow.

Project = {
    // All the variables/constants/objects that need to be globally accessible inside the Project object.

    init : function(){
        // Main entry point...
        this.MainMenu.init();

        // Rest of the code which should execute the moment Project is initiated.
    }
}

Project.MainMenu = {
    // All the variables/constants/objects that need to be accessible only to MainMenu.

    init : function(){ // Is run immediatelly by Project.init()
        // Event handlers relevant to the main menu are bound here

        // Rest of the initialization code
    }
}

Project.SlideShow = {
    // All the variables/constants/objects that need to be accessible only to SlideShow.

    init : function(){ // Is run only on pages that really require it.
        // Event handlers for the slideshow.
    }
}
Answer

Despite what other people may think, I think there are redeeming value to inlining listeners in markup. Specifically, it gives you a lot more freedom to modifying the DOM nodes. If you're adding listeners though JavaScript, the listeners are lost when you replace the innerHTML of any parent nodes. If you're inlining the listeners in markup, you can clone the node, make modifications to it, then replace the original node with the node you just cloned and modified.

Perhaps it's better to describe it in a specific use case. I want to make changes to multiple part of the document without triggering reflow multiple times. So in this case, I can clone the node, make any change to it (no reflow since its detached), then replace the previous node with the modified one (triggering one reflow). With inlined listeners, this prevents any listeners from getting lost during the replacement.

Answer

I see some saying there needs to be a separation of concerns regarding Presentation and Business Logic.

OP in his example does indeed show this separation! There is no logic in the inline event handler, but merely a function reference/call that will get executed on the "click" event... the logic itself can be separately maintained elsewhere.

I personally prefer this approach due to logical flow discoverability. If I have never seen an application before... the first place I'm going to begin my code traversal is in the DOM, and right there it will be clear which event handlers are in play and which functions are providing the logic to the handlers. With using, say a "JQuery.On" eventing approach, by just glancing through the html you would have no idea which handlers are actually wired up and providing functionality.

Inline event handlers that simply provide pointers to functions is simply wiring up the events and not leaking logic into presentation.

Answer

You could say the same about CSS and including inline styles. It would be easy to not have to wade through a css file to find the current class/id, or parent/child elements your working with.

Is it really better to bind a click to say 10 different items inline? Or just one event handler targeting a class? Even if you don't need 10 click handlers its always a better idea to set your code up for maintainability, and upgrades down the road.

Answer

Apart from the coding standards perspective

Using Attributes:

<p id="element" onclick="doSomething();">Click me</p>

if you add the same attribute again (see below) -the latest one is considered.

<p id="element" onclick="doSomethingMore();">Click me</p>

Using Event Handler:

document.getElementById('element').onclick = doSomething;

and lets say you added the below line

document.getElementById('element').onclick = doSomethingMore; Both the handlers are invoked.

Answer

I'm not aware of and advantage of using inline handler vs attach the handler later. In my experience I prefer to use the inline method when I have to deal with dynamic elements, for example if I want to add an handler to each image and the number of images changes according to other data (ex images in db). In this case using inline allow me to add an handler to each image, otherwise i have to recalculate the number of images in the javascript file to attach and handler to each image.

Of course, when you can use libraries like jQuery where you can easily get the list of elements inline aren't useful

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us Javascript

©2020 All rights reserved.