Reputation: 5407
I've seen a lot of jQuery code like this, needless to say I don't like it:
<div id="myDiv">
<a class="clickable" href="#">Click Me</a>
<a class="clickable" href="#">Click Me</a>
<a class="clickable" href="#">Click Me</a>
<a class="clickable" href="#">Click Me</a>
</div>
<script>
$(document).ready(function(){
$('clickable').click(function(){
// Do some stuff...
});
});
</script>
I realize people are doing this because the above event binding and handling requires the html structure to be available on the page, but it leads to mixing the presentation, logic and configuration all over the views of the web site. Also, it makes it very hard to debug the logic with just about any debugger out there.
So, I've started coding like this, on a separate .js file (fiddle here):
// BEGIN: Event Handlers
var onLoad = function(){
$('.clickable').data('clicked', false);
};
var onMyDivClick = function(){
var clicked = $(this).data('clicked');
if (clicked) {
$(this).trigger('myCustomEvent');
} else {
alert('you clicked me');
$(this).data('clicked', true);
}
};
var onMyCustomEvent = function(){
$(this).css('color', 'dimGray');
alert('please don\'t click me again');
};
// END: Event Handlers
// BEGIN: Event Binding
$(window).on('load', onLoad);
$(document).on('click', '.clickable', onMyDivClick);
$(document).on('myCustomEvent', '.clickable', onMyCustomEvent);
// END: Event Binding
Now, I don't need to care about the structure being on page. I don't need to wrap everything inside $(document).ready(function(){});
And I don't need to care if the structure is going to be loaded with ajax or not.
Question 1
Are there any downsides on the approach? So far, I haven't found any. But before refactoring bulk of the code on our sites, I would like to hear about the possible caveats.
Question 2
How could this approach be taken even further with the latest jQuery features?
Upvotes: 5
Views: 286
Reputation: 2484
This screams over engineering to me. In order to avoid code in document.ready, and avoid view logic in the view, you introduce even more complexity.
Your approach binds directly to document and then checks the dom for what's clicked. You then fire a second event for what's clicked, which is where your logic lives.
That's fine for one or two elements. That's not your typical app. What happens when you have 5 elements that all need to do something different? How about 10? Maybe 15?
Your "simple" event handler is going to become a nice big switch (or worse, ifs and nested ifs). Suddenly adding a new handler isn't so easy. Nor is changing an existing event.
You'd be far better off looking into a framework that provides you the separation you're looking for. Attempting to shoe horn something like this in to "help" organize your code will come back to bite you. Most complexity in code is born out of an engineer making it "simple" and "better" and "future proof".
This is not to knock you or your thoughts. You have the right idea: separation of responsibility is a good thing. I just don't think your approach is the best.
As another posted answered, angular and backbone and ember (and many more) provide the means of accomplishing what you want. Plus, you don't have to maintain whichever library you chose :)
Upvotes: 0
Reputation: 4705
Check out the frameworks, they've done the boiler-plate work for you. I've only used knockout so far, but I'll link to some others.
"Hello World" in knockout:
http://knockoutjs.com/examples/helloWorld.html
<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>
<h2>Hello, <span data-bind="text: fullName"> </span>!</h2>
// Here's my data model
var ViewModel = function(first, last) {
this.firstName = ko.observable(first);
this.lastName = ko.observable(last);
this.fullName = ko.computed(function() {
// Knockout tracks dependencies automatically. It knows that fullName depends on firstName and lastName, because these get called when evaluating fullName.
return this.firstName() + " " + this.lastName();
}, this);
};
ko.applyBindings(new ViewModel("Planet", "Earth")); // This makes Knockout get to work
Upvotes: 0
Reputation: 8524
There is one downside I know with this approach. It is written in the Event performance section in .on()
.
Attaching many delegated event handlers near the top of the document tree can degrade performance. Each time the event occurs, jQuery must compare all selectors of all attached events of that type to every element in the path from the event target up to the top of the document. For best performance, attach delegated events at a document location as close as possible to the target elements. Avoid excessive use of document or document.body for delegated events on large documents.
So after you binding all events to document
, it would perform worse.
And in Additional notes, there are some thing can't work with this approach, such as load
, scroll
, and error
.
Upvotes: 1