jQuery: Is using children() more efficient than using child selector - javascript

I often need to setup jQuery events on li tags that don't have a class or ID associated with them like in this example:
<div id="menu">
<ul id="nav">
<li>Nav Item 1</li>
<li>Nav Item 2</li>
<li>Nav Item 3</li>
<li>Nav Item 4</li>
<li>Nav Item 5</li>
</ul>
</div>
My understanding is that jQuery selecting reads from right to left so if I were to use a $('#nav > li) jquery selector it would have to search through all of the li tags and then evaluate whether the li tag had a parent with the id of nav.
Assuming this page has 30 li tags but I only want to select the 5 in the example, would it be more efficient to use $('#nav').children('li') ? My logic is that it will quickly find the #nav ID and then will only have 5 elements inside of it to search through.
An additional question I have is If there were more than 30 child elements to #nav would it then be more efficient to use the child selector $('#nav > li')?
Thanks in advance

After having to try and create a custom selector, I was surprised to find that selectors are indeed evaluated right to left.
That means $('#nav > li') will first find all LIs in the page, then filter those to retain any having id="nav" in their immediate parent.
$('#nav').children('li') will be faster for the reasons above and what you assumed (which was correct).
The other side of the coin is "do you care?". If, for instance, you are only interested in mouse events, then the speed is driven by human interaction (at most a few times per second), whereas the speed difference in your selector methods would only be noticeable if you could do it 50,000 times per second. basically you will not normally care, but you should err on the side of efficiency when you can :)
if you were just after this to add mouse events, say click, using a single delegated event handler, attached to an ancestor element, will be very efficient:
e.g.
$("#nav").on('click', 'li', function() {
// DO SOMETHING HERE - "this" IS THE LI CLICKED
});
This is efficient because it works as follows:
Listen for click events bubbling up the DOM to the single id="nav" element we listen to.
Then apply the jQuery selector against the elements in the bubble chain.
Then apply the function to the matching element that caused the event.
This technique also means it will work for dynamically added objects as they only need to match the selector at event time (not event-registration time).
Notes:
If no convenient ancestor is available to target, use document as the default for bubbled events.
Do not use 'body' for delegated event handlers as styling can stop body receiving bubbled mouse events (if it has a calculated height of zero). Use document as your fallback.

Related

click.delegate for ul items in AureliaJS

Given ul list defined as below:
<ul click.delegate="onListItemClick()">
<li repeat.for="suggestion of suggestions">
${suggestion.name}
</li>
</ul>
How do I pass suggestion object to onListItemClick? I know I can put click.delegate on each individual li element and then capture current suggestion but won't it go against event delegation idea? I mean - then I will have multiple event handlers attached, and if so I could just go with click.trigger. I don't want to do this, because there may be tons of these suggestion objects.
Put the click handler on the li element. That's the whole point of event delegation with Aurelia. It allows you to do stuff just like this without the overhead of creating a bunch of event handlers. There's just one event handler that is created by the framework for you. It delegates the calls. All of the elements click event will be set to the same function and Aurelia will handle calling your VM method.
Here's a gist.run: https://gist.run/?id=406bf3bc73e415db7afa7d46d7e958d3
<template>
You clicked suggestion id "${clickedId}"
<ul>
<li repeat.for="suggestion of suggestions" click.delegate="handleClick(suggestion)">
${suggestion.name}
</li>
</ul>
</template>

children vs selector - jQuery

For the sake of simplicity I'll narrow down the question as below. I have a large code running in the click js functions. To represent that All I have added an alert()
HTML
<ul>
<li>Test li 1</li>
<li>Test li 2</li>
<li>Test li 3</li>
<li>Test li 4</li>
<li>Test li 5</li>
</ul>
JS
Method 1
$('ul li').click(function(){alert('hi');});
Method 2
$('ul').children().click(function(){alert('hi');});
Method 1 and method 2 both works fine.
Which one is better ? Is it better to use the selector or use the children method ? What's the purpose of having a children method when we can use selector?
Test Fiddle
I'm just grabbing the basics and hope not knowing something is not a crime. Thanks
While both of those pieces of code work correctly on the sample HTML they are not identical.
.children returns all child elements (whether they are an "li" or not).
"ul li" as a selector returns all "li" descendants of the "ul" whether they are children or not.
These two are equivalent and select only "li" children of the "ul" parent:
$('ul > li').click(function(){alert('hi');});
$('ul').children("li").click(function(){alert('hi');});
As for which is better (the original question), there is no real answer for this I suspect and will depend on your actual requirements and html (when you ask for which is 'better' what do you mean? Performance? Maintainability?).
Usually the former will use the CSS selector engine of the browser where the selector you are using is supported, and the later will always use jquery built code (I think) so I would go for the former in most cases.
as to
Which one is better ?..
updated
actually, it depends on the HTML structure... if incase, you have small number of <li>'s in ul (first level) going with children selector is better
you can check this in js.perf...link here
but if you have large number of <li> (in first level) the children selector gets slower ..

How does Backbone.js keep track of DOM elements without using IDs?

Background
I have been using Backbone.js for some time and one aspect of it that impresses me is how it allows me to simplify, abstract and reuse DOM elements as 'views'. I have tried to read through some of the annotated source and am familiar with JQuery, but have little knowledge of how the DOM works on a deeper level.
Question
How does Backbone.JS tie DOM elements to views without assigning an id, class or other attribute to them?
i.e.
<ul>
<li>Item one</li>
<li>Item two</li>
<li>Item three</li>
</ul>
I love that Backbone does this and would like to know how it does it!
In javascript, a variable can hold a reference (i.e a programmatic thing that "refers to") to some element of the DOM, which is just a Javascript object. Backbone makes sure that for a view, at least that element exists. For example, in jQuery, when you refer to the third item in your list:
var item3 = $('ul li').eq(2);
(It's a zero-offset list, the first item is at index 0, the third at index 2), you can now change the text from "Item three" to "Item three point one four one five nine" with ordinary jQuery DOM manipulators:
item3.text("Item three point one four one five nine");
Even though that list item doesn't have any particular class or ID attributes.
A backbone view's el field contains a constant reference to the parent element in which that view renders all of its stuff. Backbone uses the jQuery delegate event manager to attach a generic event handler to that one constant reference. Whenever an event happens within that DOM element or any of its children, the delegate catches the event, along with a reference to the specific DOM object within the parent el that created the event, and backbone uses some fairly standard jQuery magic to map that to an event handler in the view.
It is, indeed, very cool stuff.
I should add that the "constant"-ness of the el reference is, er, arguable. If you're attaching view logic to an existing HTML element, you do assign to the el once, in the view's initialize(). Javascript doesn't enforce any notion of constantness, but you should only directly assign to el (ie this.el = something()) if you're sure you know what you're doing.

Getting element properties in click handler

Forewarning: I'm a newbie to JQuery.
I have a collection of links and lists that look something like so. They're dynamically generated by my back end framework...
<ul>
<li>
<a id="link1" class="special" href="#">...</a>
<ul id="list1"> ... </ul>
</li>
<li>
<a id="link2" class="special" href="#">...</a>
<ul id="list2"> ... </ul>
</li>
<li>
<a id="link3" class="special" href="#">...</a>
<ul id="list3"> ... </ul>
</li>
</ul>
I'm trying to learn JQuery and Unobtrustive Javascript, so I want to add a click handler on all the links with the class "special" that will toggle the related lists.
So...
$(document).ready(function() {
$("a.special").click(function() {
id = *magicFunctionToGetOwnID*
$(convertListIDtoLinkID(id)).toggle
})
})
What is the magic function that I need? What about if I want to get other properties of the thing I'm attaching a handler to? Say, in the future, I add a "toggle-target" property and I would want to get that?
Not sure If I get you right, but it looks like you want something like this:
$(function() {
$('ul:first').delegate('a.special', function( event ) {
$(this).next('ul').toggle();
});
});
You don't should bind an event handler to all nodes in a situation like that. It's enough to bind one handler to a shared parent and make use of the event bubbling.
Update
.delegate() does exactly what I described above. It'll bind the event handler to a node. The trick is, that event if that event is triggered on a child node from the delegated node, the events will "reach" our destination by bubbling up the DOM tree (unless explicitly prohibit event bubbling). However, jQuery is nice and will always bind this to the target node (the node which originally received the event).
Have a read: http://api.jquery.com/delegate/
Try $(this).parent().find("ul").toggle(). It is rather self-explanatory.
http://jsfiddle.net/gLu9a/
The way to get an element's own id is with the id property. The element that was clicked is set as this within the handler, so you can use this.id.
That said, this is not an optimal technique. Use DOM relationships, rather than setting ids, wherever you can. This will make your code more flexible and intuitive. In this case, you can use the next method, to get the DOM element that follows the element that was clicked:
$(this).next().toggle();
See the API "traversing" category for more ways of adjusting a selection.

Toggle multi-level ul with mootools

Greetings,
I would like to toggle a huge multi-level ul with mootools 1.1 or plain javascript.
The list looks like:
HTML:
<ul>
<li>aaa</li>
<li>bbb</li>
<li>ccc</li>
<li>
<ul>
<li>ddd
<ul>
<li>fff</li>
<li>ggg</li>
</ul>
</li>
<li>eee</li>
</ul>
</li>
</ul>
What I would like to do initially is to show the first level expanded, and the other levels collapsed and when each of the list items is clicked, to expand the ul below it.
Is it possible to do it without (greatly) modifying the html above?
From the documentation, I see that Fx.Slide is the most appropriate, however it accepts the id of the element as a parameter, which means I have to assign id's to each list item.
Is there a way by using selectors of collections of elements starting from the top?
I'm not sure whay I'll say apply with the very old 1.1 version. However, at least since 1.2, the element you need to pass is either the ID (like you said), either the actual element.
If you can use another version than 1.1, try the 1.3 which makes it easier to select the elements you want.
Here, I believe you need every <ul> element which has a direct <li> as parent. MooTools 1.3 features this new selector engine Slick, which would accomplish it fairly easilly: ul !> li.
However, I'm not sure (I didn't success) that the direct child selectors works properly with 1.1.
Here is what I came up with: http://jsfiddle.net/rCfwq/

Categories

Resources