views:

168

answers:

5

Hi Folks

How do I limit an event to a single element in a jQuery collection?

In the case below, I've tried using .one() to limit the behaviour (inserting the <li class='close'>Close</li> line of HTML) to a single instance. The behaviour does indeed happen only once, but on EVERY matched element of $( "ul>li>a" ). How do I make it happen only once, to only ONE of the matched elements in the collection?

Any ideas?

$( "ul>li>a" ).one(
 "click",    
 function(){
  $( "ul ul")
  .prepend("<li class='close'>Close</li>")
 }
 ); 

Thanks in advance.

-AS

+1  A: 

Try first(), it selects the first element:

$( "ul>li>a" ).first().one('click',    
     function(){
        $( "ul ul").prepend("<li class='close'>Close</li>")
     }
 ); 

one() is used, as you already noticed, to handle an event only once.

Felix Kling
This will not work. Read the documentation.
SLaks
@SLaks: I was too fast with copy and past ;) Thanks.
Felix Kling
A: 

You can call the first method, which will return a new jQuery object containing only the first element in the original one.

However, in your case, you might as well use the (equivalent) :first selector, like this:

$("ul > li > a:first").click(function() { ... });

If you only want to handle the first click event and ignore any subsequent clicks, you'll need to use .one(), like you already are.

SLaks
A: 

A jQuery selection returns an array. Therefore $("selection")[0] can work. However there are better abstracted methods for this, like .get(0) or .first() (in case you're looking for the first element of the selection/array).

$("selection").get(index) returns the pure DOM element (at that specific index) of the selection, and is not wrapped in the jQuery object.

$("selection").first() returns the first element of the selection, and wraps it in a jQuery object.

So if you don't necessarely want to return the first element, but still want jQuery functionality, you can do $($("selection").get(index)).

Given your situation, this should work fine:

// bind the 'onclick' event only on the first element of the selection
$( "ul>li>a" ).first().click(function() {
    $( "ul ul").prepend("<li class='close'>Close</li>");
}); 

Which is equivalent to this:

$($( "ul>li>a" ).get(0)).click(function() {
    $( "ul ul").prepend("<li class='close'>Close</li>");
});

And this:

$($( "ul>li>a" )[0]).click(function() {
    $( "ul ul").prepend("<li class='close'>Close</li>");
});

I must disagree with Ryan, working on the CSS selection string to filter the result is rather expensive compared to the native JavaScript array functionality.

Luca Matteis
+2  A: 

You have to specify the index of the element you want to work with.

If your selector returns more than one element you can do one of a couple things... You can isolate your elements by giving them a class or id attribute in your html and alter the selector to select only the class/id of the element/s you wish to select or you can specify the index of the element you're trying to work with. The later method is a bit sloppy but works as long as your page structure doesn't ever change.

So for the first method I spoke of you'd change your selector to this after applying a class/id to your elements:

$("ul>li>a.class")
or
$("ul>li>a#id")

For the second method I mentioned you'd change your selector to this:

$("ul>li>a:eq(index)")

Where index is the zero based index of the element you're trying to select.

Ryan
A: 

You need to combine first() with one():

$( "ul>li>a" ).first().one('click', function () {});

More general:

$( "ul>li>a:eq(n)" ).one('click', function () {});
kgiannakakis