AngularJS - multiple ng-click - event bubbling
Asked Answered
T

2

40

In the following example:

  <li ng-repeat="item in items" ng-click="showItem(item)">
    <h3>{{item.title}}</h3>
    <button ng-click="remove(item)">Remove</button>
  </li>

When I click on the button showItem() also is invoked due to event bubbling. I know that I can use $event to watch for $event.currentTarget and do $event.stopPropagation() etc. but this is very ugly.

Btw. I don't want to stop propagation on the button (In my case the button is a twitter bootstrap dopdown/button - this is just an example)

How do I stop showItem() from beeing called when I click on the remove button?

EDIT The ugly fix would be to have:

function remove(item,$event){
  $event.originalEvent.prevent = true;
  // rest of the code
}

function showItem(item,$event){
  if($event.originalEvent.prevent)return;
  // rest of the code
}
Transceiver answered 22/5, 2013 at 20:32 Comment(1)
If you can't use stopPropagation, you will have to restructure your dom so they're not nested. Is that possible?Reminiscent
M
63

This solution worked for me (I'm only supporting recent browsers, so I tried to modify the code to be more retro-compatible):

HTML:

<li ng-repeat="item in items" ng-click="showItem(item)">
    <h3>{{item.title}}</h3>
    <button ng-click="remove(item, $event)">Remove</button>
</li>

Scripts:

function remove(item, $event) {
    // do some code here

    // Prevent bubbling to showItem.
    // On recent browsers, only $event.stopPropagation() is needed
    if ($event.stopPropagation) $event.stopPropagation();
    if ($event.preventDefault) $event.preventDefault();
    $event.cancelBubble = true;
    $event.returnValue = false;
}
function showItem(item) {
    // code here
}

EDIT - Added a JSFiddle demo to try it out http://jsfiddle.net/24e7mapp/1/

Memory answered 13/6, 2013 at 15:30 Comment(7)
This method didn't work for me on Chrome Version 35.0.1916.153 m, but $event.stopPropagation() did. I didn't need the $event.returnValue.Scoff
Exactly. In Chrome (and other modern browsers), you can stop at the first line: $event.stopPropagation(); (without the 'if'). But as specified in the comments, if you need to make it work in IE8 et less, you have to use $event.preventDefault() or the cancelBuble/returnValue. Maybe one of those two aren't required, I can't remember exactly.Memory
@Ron, please check out the demo and try it on different browser versions.Memory
Both $event.cancelBubble = true; and $event.returnValue = false; breaks Chome/ium (tested on 43.0.2357.130).Imply
@Imply You could simply to a check before, like so: if ($event.cancelBubble) { $event.cancelBubble = true; }.Memory
@Memory Why setting cancelBubble true when it already evaluates to true (otherwise the condition won't be ever satisfied).Met
@cepharum Sorry, you're right, I wrote it too fast. Should have been: if (typeof $event.cancelBubble === 'boolean') $event.cancelBubble = true; BTW, this has no effect on Chrome 58 and Opera 45 (see ref)Memory
B
0

showItem can be updated to return early if the passed in item no longer exists:

function remove(item) {
  if (-1 == $scope.items.indexOf(item)) {
    // Item no longer exists, return early
    return;
  }
  // Rest of code here
}
Brilliant answered 22/5, 2013 at 21:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.