I have always missed a traverse function in jQuery, and I thinking that there might be one but I missed it. Say we have the following markup:
<ul>
<li><a href="#">Foo</a></li>
<li><a href="#">Bar</a></li>
<li><a href="#">John</a></li>
<li><a href="#">Doe</a></li>
</ul>
Now, if I want to add an active class to the anchor I clicked and deactivate the others, I would normally have to do this:
$('a').click(function() {
$(this).addClass('active')
.parent()
.siblings()
.find('a.active')
.removeClass('active');
});
But what I want is to do is this:
var relation = function() {
return $(this).parent().siblings().find('a.active');
};
$('a').click(function() {
$(this).addClass('active').find(relation).removeClass('active');
});
See the difference? Now, find doesn’t take a function as argument, so I wrote something like this:
$.fn.traverse = function(fn) {
return $.isFunction(fn) ? fn.call(this) : this;
};
As an example, this simple method makes it possible to create an “activate” plugin that lets the author specify the relationship to the deactivations:
$.fn.activate = function(fn) {
return this.each(function() {
$(this).addClass('active').traverse(fn || function() {
return $(this).siblings();
}).removeClass('active');
});
});
And use it like this:
$('a').activate(function() {
return $(this).parent().siblings().find('.active');
});
// or
$('a').activate(function() {
return $(this).closest('ul').find('a.active').not(this);
});
// or
$('li').activate();
This will do the job. But my question is that there really should be something like this included in jQuery somewhere, no? I was looking at .map but it doesn’t work that way.
The usual pattern in jQuery is:
find the elements you want to change, then
call a method to do something to them.
There are many other ways you could do things, but this way works fine and it is the way the library is designed to work. I would need a compelling reason to depart from that. (Not just “But I want to do it this way.”)
I would write it like this:
Chaining is overrated. If you want to do two things, try writing two lines of code. You might like it!