I like the way jQuery wraps events when you use its "bind" method. However it's awkward to set up the bindings. Is there any way to combine the ease of html (e.g. onKeyPress="foo(event)" ) with jQuery's browser-independent event-handling goodness?
You mean like this?
function foo(event) {
alert(event.target);
}
$('.someSelector').keypress(foo);
Whether in HTML or javascript way you need to create a function foo, so maybe this is closer to what you were looking for.
I'm not sure what exactly you feel is awkward about jQuery's handler binding.
You probably don't want to do that.
You may want to read up on event delegation in JavaScript, which those jquery binding methods handle neatly for you.
Here's the highlights:
Event delegation has several benefits
to the performance of a web
application:
Fewer functions to manage. Takes up
less memory. Fewer ties between your
code and the DOM. Don’t need to worry
about removing event handlers when
changing the DOM via innerHTML.
You're better off using jQuery's binding helpers like $whatever.click(fn) etc.
Actually here is another question on SO that references the same article I did that may also help.
A good idea is to actually separate the two, to have your HTML clean and the js in a separate location. You can try shortcuts like $('a').click(...) instead of $('a').bind('click'...), but that's about it. Personally I like having the bindings separate from the markup.
Related
HTML event attributes:
<button id="myButton" onclick="someFunction()">Click me</button>
jQuery event methods:
$('#myButton').click(function () { alert('Hello'); });
Which way is more appropriate and gives better performance?
Which way is better?
The latter, or any of the other modern ways of doing it (addEventListener, etc. — e.g., you don't need jQuery for this, although you can use it for this if you like). onxyz-attribute-style handlers are generally a poor choice because:
They can only call global functions. In general, you want to avoid having global functions.
They force you to mix your code and HTML, rather than keeping them distinct. (This could be considered subjective.)
Note that this doesn't mean you need to have an id on every element; you can use the full power of CSS selectors to find elements (with jQuery, or with querySelector/querySelectorAll) in order to hook them up, they don't have to have ids.
Do be sure that your code runs after the element is known to exist. Generally, the known best practice is to put your script tags at the end of the document, just prior to the closing </body> element; at that point, all elements defined by the HTML above the script will exist.
For performance the vanilla JS methods are better, however this is usally not significant. The loss in performance occurs because the JQuery library has to be loaded in order to execute the JQuery event methods. If you only are using JQuery very little you could consider replacing it with vanilla JS for performance.
Also in your first case you are mixin JS and html which is often bad we the amount of JS is growing because your files will be harder to read. Usually it is best practice to seperate concern (put JS/CSS in seperate files from html)
Never done html or any related projects before. Though as relatively straightforward as it appears so far. I still need some of you wisdom. I'm making a form.
A html form has an attribute onsubmit to which I can assign a function for it to call.
<... id="formId" onsubmit="aFunction();" >
I can also get the onsubmit attribute via the document.getElementById("formId").onsubmit etc.
Is one method preferable to the other? And am I right in thinking the getElementById would override any functions assigned to be called in the HTML form tag?
The later one is preferable (using .onsubmit in Javascript) since it modularizes your code. Modularization in the sence that it seperates the Javascript code from your HTML. So, your .HTML files will contain only HTML code and .js files will contain only Javascript code.
This way it is easy to maintain the code of the project.
You are right that setting onsubmit will override other event handlers. The alternative is to use addEventListener, which will allow you to bind multiple event handlers to an event.
I think binding the event in JavaScript is the best way to go. Your HTML markup should be clean, without these kinds of logic in it. Of course this is a matter of opinion, but I'm pretty sure the balance is tilting to this opinion. :)
A quick note: IE8 doesn't support addEventListener, but you can use the similar attachEvent for that browser. For that and more information about addEventListener, see:
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener
Which functions needs to be overwritten to recognize any DOM content changes (Application-Side), including plugins like jquery ? Do not suggest Mutation.
You might want to take a look at this technique that relies on CSS animation keyframes.
As said above, mutation specs are either deprecated or not implemented yet.
You can try using jQuery itself and bind a handler to the DOMSubtreeModified event.
$(document).on('DOMSubtreeModified', function() {
console.log('changed');
})
There is actually a warning on w3.org that says it is deprecated. This is the only way I know of, though.
In my answer to the following SO question: What does event binding mean?, I made a passing remark that the use of inline-JavaScript/Early-Binding to bind JavaScript Events was 'often misguided'
For example:
<input id="MyButton" type="button" value="clickme" onlick="Somefunction()" />
I was arguing for the 'late-binding' approach where there is no JavaScript referenced in the markup, which I understand to be established best-practice. However, the commenters asserted that there were occasions that necessitated its use, and I wondered what these might be.
Without engaging in a discussion on the relative merits of either, can anyone think of any circumstances that dictate that you use the (e.g.) onclick attribute over a late-binding approach.
commenters asserted that there were occasions that necessitated its use
I suppose I'm one of those commentors. What I actually said was that inline listeners "are a reasonable option in certain circumstances". I don't think there are any cases where it is "necessitated" (which I understand in this context to mean required).
Adding inline listeners is simply applying the same logic on the server to add listeners as would be applied on the client and has advantages in that:
Markup can be created and cached or used as static pages, listeners aren't added by every client over and over again when pages are downloaded
Issues related to delay between the element being available and the listener being added by DOMReady or onload functions or "bottom scripts" are completely removed
The vagaries of various "cross browser" DOMReady functions with onload fallback are removed - there is no opportunity for such functions to fail to add listeners if they aren't used
Of course this doesn't mean that all listeners should be added inline and that dynamic addition of listeners is rubbish, I'm just point out that it is a viable method that solves certain issues and is a perfectly reasonable solution in many cases.
If you believe "early binding" of listeners is good, then make it as early as possible - put them inline. :-)
PS. I also think I said I didn't like the use of "binding" in this context as listeners aren't bound to elements in any real sense. They are simply functions that are called when an element receives a related event. The only type of binding is that the listener's this keyword may be set to reference the related element (which is consistent in all browsers for inline listeners but not necessarily for those added later).
Reasons why onclick attributes are bad :
onclick="foo()"
Your passing in a string of code that get's evalled at runtime when the element is clicked. This is inefficient and uses the horrors of eval
Your forced to store the function foo in global scope thus polluting global scope with all your event handling logic.
I think many developers will do this either due to ignorance or lack of knowledge (which is, of course, common) and the remaining developers will do it because it's simply more convenient to use HTML-JS attributes than late binding, if you know that certain objects and functions are always loaded on every page and they will simply 'be there'.
I think this is especially true when said HTML comes from an AJAX callback. Take an example where an AJAX request comes back with an HTML response and that HTML is inserted into the page. Now the naive developer would think along these lines:
I have no idea what elements are inside that response HTML so I don't know what late bindings I need to add.
Perhaps I need to add them all just in case! Or write some parsing script that detects elements and binds to the ones I find?
But what if I need to bind to something that doesn't already exist? Time to write some long inline JavaScript!
All of this can be eliminated by using a kind of omnipresent binding that applies to all current and future elements on the page. In jQuery, the equivalent is live(). Instead of writing:
$('.foo').click(function(){...});
You could write:
$('.foo').live('click', function(){...});
Now, all elements with class name 'foo' will execute the function when clicked, including elements that don't currently exist. Very useful for dynamic AJAX interfaces.
You may know that already, but I'm just pointing out that anything JS attributes can do, pure JS can do better, and I'd consider that best practise.
I see 2 main ways to set events in JavaScript:
Add an event directly inside the tag like this:
do foo
Set them by JavaScript like this:
<a id="bar" href="">do bar</a>
and add an event in a <script> section inside the <head> section or in an external JavaScript file, like that if you're using prototypeJS:
Event.observe(window, 'load', function() {
$('bar').observe('click', doBar);
}
I think the first method is easier to read and maintain (because the JavaScript action is directly bound to the link) but it's not so clean (because users can click on the link even if the page is not fully loaded, which may cause JavaScript errors in some cases).
The second method is cleaner (actions are added when the page is fully loaded) but it's more difficult to know that an action is linked to the tag.
Which method is the best?
A killer answer will be fully appreciated!
I think the first method is easier to read and maintain
I've found the opposite to be true. Bear in mind that sometimes more than one event handler will be bound to a given control.
Declaring all events in one central place helps to organize the actions taking place on the site. If you need to change something you don't have to search for all places making a call to a function, you simply have to change it in one place. When adding more elements that should have the same functionality you don't have to remember to add the handlers to them; instead, it's often enough to let them declare a class, or even not change them at all because they logically belong to a container element of which all child elements get wired to an action. From an actual code:
$$('#itemlist table th > a').invoke('observe', 'click', performSort);
This wired an event handler to all column headers in a table to make the table sortable. Imagine the effort to make all column headers sortable separately.
In my experience, there are two major points to this:
1) The most important thing is to be consistent. I don't think either of the two methods is necessarily easier to read, as long as you stick to it. I only get confused when both methods are used in a project (or even worse on the same page) because then I have to start searching for the calls and don't immediately know where to look.
2) The second kind, i.e. Event.observe() has advantages when the same or a very similar action is taken on multiple events because this becomes obvious when all those calls are in the same place. Also, as Konrad pointed out, in some cases this can be handled with a single call.
I believe the second method is generally preferred because it keeps information about action (i.e. the JavaScript) separate from the markup in the same way CSS separates presentation from markup.
I agree that this makes it a little more difficult to see what's happening in your page, but good tools like firebug will help you with this a lot. You'll also find much better IDE support available if you keep the mixing of HTML and Javascript to a minimum.
This approach really comes into its own as your project grows, and you find you want to attach the same javascript event to a bunch of different element types on many different pages. In that case, it becomes much easier to have a single pace which attaches events, rather than having to search many different HTML files to find where a particular function is called.
You can also use addEventListener (not in IE) / attachEvent (in IE).
Check out: http://www.quirksmode.org/js/events_advanced.html
These allow you to attach a function (or multiple functions) to an event on an existing DOM object. They also have the advantage of allowing un-attachment later.
In general, if you're using a serious amount of javascript, it can be useful to make your javascript readable, as opposed to your html. So you could say that onclick=X in the html is very clear, but this is both a lack of separation of the code -- another syntactic dependency between pieces -- and a case in which you have to read both the html and the javascript to understand the dynamic behavior of the page.
My personal preference is to use jQuery in external js files so the js is completely separate from the html. Javascript should be unobtrusive so inline (ie, the first example) is not really the best choice in my opinion. When looking at the html, the only sign that you are using js should be the script includes in the head.
An example of attaching (and handling) events might be something like this
var myObject = {
allLinkElements: null,
init: function()
{
// Set all the elements we need
myObject.setElements();
// Set event handlers for elements
myObject.setEventHandlers();
},
clickedLink: function()
{
// Handle the click event
alert('you clicked a link');
},
setElements: function()
{
// Find all <a> tags on the page
myObject.allLinkElements = $('a');
// Find other elements...
},
setEventHandlers: function()
{
// Loop through each link
myObject.allLinkElements.each(function(id)
{
// Assign the handler for the click event
$(this).click(myObject.clickedLink);
});
// Assign handlers for other elements...
}
}
// Wait for the DOM to be ready before initialising
$(document).ready(myObject.init);
I think this approach is useful if you want to keep all of your js organised, as you can use specific objects for tasks and everything is nicely contained.
Of course, the huge benefit of letting jQuery (or another well known library) do the hard work is that cross-browser support is (largely) taken care of which makes life much easier
Libraries like YUI and jQuery provide methods to add events only once the DOM is ready, which can be before window.onload. They also ensure that you can add multiple event handlers so that you can use scripts from different sources without the different event handlers overwriting each other.
So your practical choices are;
One. If your script is simple and the only one that will ever run on the page, create an init function like so:
window.onload = function () {
init();
}
function init() {
// actual function calls go here
doFoo();
}
Two. If you have many scripts or plan to mashup scripts from different sources, use a library and its onDOMReady method to safely add your event handlers