6

Is there is a way to only let the inner element of a listitem do something?

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

The inner a tags 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 ");
Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
Richard
  • 4,516
  • 11
  • 60
  • 87
  • Could you please post more code? What is getting dynamically appended? Both the `a` and the `li`? Just the `a`? Is the click for the `li` using `bind()` and the `a` is using `live()`? – user113716 Feb 23 '10 at 20:48
  • The li items are dynamicly added at the beginning There is an extra a tag added to the list items at a later stage when a checkbox is clicked. I check with hasClass wich one is clicked. I guess i have a bind and a live event then – Richard Feb 23 '10 at 21:01
  • ok, you are saying,I should use live consistantly. I can definitivly try that out, and also try out the solution from @Alex. I can be back later to verify if one or the other or both worked. Thank you both for the valuable input sofar. – Richard Feb 23 '10 at 21:30
  • Alex offered the key to an excellent solution. Please see his answer. – user113716 Feb 23 '10 at 23:48
  • You shuld be wary of using 'return false'. Use e.preventDefault or e.stopPropogation instead – Paul Sullivan Jul 15 '12 at 09:58

3 Answers3

9

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
  • 10,401
  • 2
  • 29
  • 41
  • 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 Feb 23 '10 at 20:30
  • 1
    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 Feb 23 '10 at 20:40
  • 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 recognize that 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 Feb 23 '10 at 20:48
  • 1
    I added a simple example of how to use `bind` even though you're adding new elements to the list. – Alex Sexton Feb 23 '10 at 20:53
  • Sorry, put the comment in the wrong section at first I 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 Feb 23 '10 at 21:18
  • 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 Feb 23 '10 at 21:20
  • Not at all. Your solution works. You were absolutely right about using 'bind'. I didn't know that about 'live'. Thanks. – user113716 Feb 23 '10 at 23:38
  • 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. – user113716 Feb 23 '10 at 23:46
  • Thanks for catching the bug, it's fixed. – Alex Sexton Feb 24 '10 at 00:06
0

Solution from Author:

I added all the a tags like above, so no mixup with live anymore.

$(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);

Here is an interesting page to explain event bubbling: How to stop event bubbling with jquery live?

Community
  • 1
  • 1
Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
-1

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

Pointy
  • 405,095
  • 59
  • 585
  • 614