63

I have a HTML structure like this:

<div ng-click="test()">
    <div id="myId" ng-click="test2()"></div>
    <div></div>
    ...
</div>

Currently when I click on the div with the id myId then both functions get triggered, but I want that just test2 function get triggered. How can I do that?

Tom
  • 26,212
  • 21
  • 100
  • 111
Safari
  • 3,302
  • 9
  • 45
  • 64
  • See also http://stackoverflow.com/questions/14544741/angularjs-directive-to-stoppropagation where a directive is defined to stop propagation. – Mark Rajcok Mar 13 '13 at 19:12

3 Answers3

123

All you need to do is to stop event propagation/bubbling.

This code will help you:

<div ng-click="test()">ZZZZZ
    <div id="myId" ng-click="test2();$event.stopPropagation()">XXXXX</div>
    <div>YYYYYY</div>
    ...
</div>

If your test and test2 functions would look as follows, you would get only test2 in your console when clicking on myId DIV. Without $event.stopPropagation() you would get test2 followed by test in the console output window.

$scope.test = function() {
    console.info('test');
}
$scope.test2 = function() {
    console.info('test2');
}
Tom
  • 26,212
  • 21
  • 100
  • 111
32

Same as tom's answer, but little different.

        <div ng-click="test()">
            <div id="myId" ng-click="test2($event)">child</div>
        </div>

        $scope.test2 =function($event){
            $event.stopPropagation();
            console.log("from test2")
        }
        $scope.test =function(){
            console.log("from test")
        }
Rajkamal Subramanian
  • 6,884
  • 4
  • 52
  • 69
  • +1 to this answer for keeping that stopPropagation logic out of the view. – sma May 07 '14 at 15:40
  • 7
    I think this logic **does** belong in the view, because otherwise controller makes the assumption that the inner function will always be called from that context, and that it will need to stop propagation every time. This makes the reuse of the inner function very limited. If the view ever gets refactored, then so must the controller. – rodrigo-silveira Apr 02 '15 at 23:12
1

Here is a directive based on another question which supports ng-href links.

Directive

'use strict';


var myApp = angular.module('myApp', [
    'ngAnimate'
  ]);

/**
 * @ngdoc directive
 * @name myMobileApp.directive:stopEvent
 * @description Allow normal ng-href links in a list where each list element itselve has an ng-click attached.
 */
angular.module('myApp')
  .directive('stopEvent', function($location, $rootScope) {
    return {
      restrict: 'A',
      link: function(scope, element) {
        element.bind('click', function(event) {

        // other ng-click handlers shouldn't be triggered
        event.stopPropagation(event);
        if(element && element[0] && element[0].href && element[0].pathname) {
          // don't normaly open links as it would create a reload.
          event.preventDefault(event);
          $rootScope.$apply(function() {
            $location.path( element[0].pathname );
          });
        }
      });
      }
    };
  })


.controller('TestCtrl', ['$rootScope', '$scope', 'Profile', '$location', '$http', '$log',
  function($rootScope, $scope, Profile, $location, $http, $log) {
    $scope.profiles = [{'a':1,'b':2},{'a':3,'b':3}];

    $scope.goToURL = function(path, $event) {
      $event.stopPropagation($event);
      $location.path(path);
    };

  }
]);
  <div ng-repeat="x in profiles" 
     ng-click="goToURL('/profiles/' + x.a, $event)">

      <a stop-event ng-href="/profiles/{{x.b}}">{{x}}</a>

  </div>
Community
  • 1
  • 1
s.Daniel
  • 1,064
  • 12
  • 29