views:

268

answers:

3

Is there is a smooth way to only let the inner element of a listitem do something? I read something here that using live complicates things.

Summation:

I have list elements that can contain a elements with a certain class.

The inner a elements are bound to a live click event handler. The list items themselves have also a click event handler.

Something like this

<li>some text<a class="someClassName">some text</a></li>

with the handler for the a tags

$('#somelist li a').live("click", function(e)

and this is how the event for li item is added

$(markers).each(function(i,marker){
    $("<li />") 
    .html("Locatie "+'<a class="ol id"><strong>'+ids[i]+'</strong></a>') 
    .click(function(e){
          showLocation(marker, i);
    })
    .appendTo("#somelist ");

Solution

Changing the click event above to .live("click", function(e) diddn't work. Instead I added all the a tags like above, so no mixup with live anymore. The solution from Alex might also work, and that way you could have all functionality contained in one function.

For now it turned out like this

$(markers).each(function(i,marker){
    listitem = $("<li />") 
    .html("Location ") 
    .click(function(e){
        showLocation(marker, i);
    })
    .appendTo("#somelist");
    $("<a />")
    .html("<strong>"+ids[i]+"</strong>")
    .addClass('ol id')
    .click(function(){
        $('#ginfo').show();
        return false;
    })
    .appendTo(listitem);

oh, and this one has a nice picture to explain the bubbling

thanks, Richard

A: 

Have the handler for the <a> tags return false.

Pointy
+8  A: 

The live method in jQuery works via event delegation, which is the act of catching all the bubbled events from individual elements onto a common ancestor (in your case its document).

Stopping the propagation/bubbling of the click event occurs on the handler element (which is the common ancestor, not on the element itself) and exists way above the li that you are trying to avoid.

So by the time the stopPropagation method gets called, we've already traversed down the dom and passed the li element.

It's essentially putting a stop sign 200ft after the intersection.

So you'll either need to use bind and stopPropagation or find a different solution.

Here is an example of what I'm talking about: http://jsbin.com/ibuxo (check the console)

you can see the code or edit it at http://jsbin.com/ibuxo/edit

My suggested solution to this problem would be to use bind instead of live.

This requires you to do a little bit extra work, but it's not so bad.

You are probably using live because you are adding new elements, and you want them to have the same functionality. You should do this by binding them when you input them to the page. Here's an example

$(function(){
  var myAnchorHandler = function(e){
    alert('clicked!');
    e.stopPropagation();
    return false;
  };

  // initial bind
  $('#somelist li a').click(myAnchorHandler);

  // code where you input more li elements to the list with links
  $('#somelist').append(
    // bind your function to the element now, and then append it
    $('<li><a>hi</a></li>').find('a').click(myAnchorHandler).parent()
  );
});
Alex Sexton
good explanation, although I do not understand the termonology completely. Any ideas on diiferent solutions maybe, I am out off ideas at the moment.
Richard
thanks for the latest update, I will check it out
Richard
I can go into more detail on it if you'd like, but more or less, if you want to be able to block something from happening on the `li` you either need to use `bind` to handle your clicks, or you need to modify whatever handler is currently on the `li` to ignore anything that originated in a child anchor element.
Alex Sexton
no, you don't have to go into more detail, I can read up on that.Right now, I am more interested in a practical solution.I there something I can do in the li click event that would recognizethat I clicked on the child a element. I already try'd something with e.target, but that will only give the li element, right?
Richard
I added a simple example of how to use `bind` even though you're adding new elements to the list.
Alex Sexton
Sorry, put the comment in the wrong section at firstI can't evalute that fast right now, but thanks, If this is the solution. You are also saying that I dont need live at all in this setup.I am going to be pleasantly surprised if this works out because the content off the page is dynamicly added and I always thought you needed live for this to work
Richard
As long as you add event handlers to your elements, their events will be handled. In the case of dynamic content, you just have to wait until you put it there to get it to work. Another solution could be having a hidden element with all the events attached to it and running a `clone(true)` on it to return a new instance with the event handlers. That's if you don't want to write html in your code or something.
Alex Sexton
Well, I see you have missed the point entirely.
Alex Sexton
Not at all. Your solution works. You were absolutely right about using 'bind'. I didn't know that about 'live'. Thanks.
patrick dw
I just up-voted you, since you seem a little perturbed right now. Didn't mean to upset you. The core concept you are communicating in your answer is spot-on.
patrick dw
Thanks for catching the bug, it's fixed.
Alex Sexton
A: 

Thanks alex, never really thought of stopPropagation(); it worked for me. Thanks a lot, good to have guys like you around :)Thanks alex, never really thought of stopPropagation(); it worked for me. Thanks a lot, good to have guys like you around :)