AngularJS - how to override directive ngClick
Asked Answered
B

2

27

I want to override directive ng-click: to some make some $rootscope changes before each execution of ng-click. How to do it?

Baritone answered 24/8, 2013 at 18:23 Comment(0)
S
32

You can't override AngularJS built-in directives. However, you can define multiple directives with the same name and have them executed against the same element. By assigning appropriate priority to your directive, you can then control whether your directive runs before or after a built-in directive.

This plunker shows how to build an ng-click directive that executes before the built-in ng-click does. The code is also shown below. When clicking the link, the custom ng-click will run first, then the built-in ng-click does.

index.html

<!DOCTYPE html>
<html ng-app="app">

  <head>
    <script data-require="[email protected]" data-semver="1.9.0" src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.js"></script>
    <script data-require="[email protected]" data-semver="1.0.7" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js"></script>
    <script src="script.js"></script>
  </head>

  <body ng-controller="MyCtrl">
    <a ng-click="alert()">Click me</a>
  </body>

</html>

script.js

angular.module('app', [])
  .directive('ngClick', function($rootScope) {
      return {
        restrict: 'A',
        priority: 100, // give it higher priority than built-in ng-click
        link: function(scope, element, attr) {
          element.bind('click', function() {
            // do something with $rootScope here, as your question asks for that
            alert('overridden');
          })
        }
      }
  })
  .controller('MyCtrl', function($scope) {
    $scope.alert = function() {
      alert('built-in!')
    }
  })
Siphonophore answered 25/8, 2013 at 3:37 Comment(4)
Buu, can we stop first ng-click totally? i mean after running 'overridden' alert, 'built-in' not to run.Success
Don't pass an expression to ng-click, see plnkr.co/edit/uROkIcGKLspLnVsjmAKn?p=preview. If you have to pass s/t, then don't handle it, e.g. $scope.alert = function() {}.Siphonophore
this is not the correct answer, checkout the Eric Chen one below!Tutuila
Concur with JackNova, this answer is not correct. * you CAN override/replace all directives as @eric-chen shows below * this example approach will run into issues - you cannot have multiple directives on the same element requesting an isolate scope or setting a template. Eric's approach solves that tooRefit
S
80

Every directive is a special service inside AngularJS, you can override or modify any service in AngularJS, including directive

For example remove built-in ngClick

angular.module('yourmodule',[]).config(function($provide){
    $provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
        //$delegate is array of all ng-click directive
        //in this case first one is angular buildin ng-click
        //so we remove it.
        $delegate.shift();
        return $delegate;
    }]);
});

angular support multiple directives to the same name so you can register you own ngClick Directive

angular.module('yourmodule',[]).directive('ngClick',function (){
  return {
    restrict : 'A',
    replace : false,
    link : function(scope,el,attrs){
      el.bind('click',function(e){
        alert('do you feeling lucky');
      });
    }
  }
});

check out http://plnkr.co/edit/U2nlcA?p=preview I wrote a sample that removed angular built-in ng-click and add a customized ngClick

Seedman answered 22/4, 2014 at 2:53 Comment(3)
How would you keep both delegates but let the first handler conditionally propagate to the built-in delegate?Thirteenth
@AlexWhite my guess is that it's impossible since the click binding is being done with element.bind inside another function callback already: github.com/angular/angular.js/blob/master/src/ng/directive/…Diaphoresis
@AlexWhite the simple solution is to simulate this behavior by making a copy of the ngClick event handler and $parse usage in your directive and calling it conditionally from your event handler.Jabber
S
32

You can't override AngularJS built-in directives. However, you can define multiple directives with the same name and have them executed against the same element. By assigning appropriate priority to your directive, you can then control whether your directive runs before or after a built-in directive.

This plunker shows how to build an ng-click directive that executes before the built-in ng-click does. The code is also shown below. When clicking the link, the custom ng-click will run first, then the built-in ng-click does.

index.html

<!DOCTYPE html>
<html ng-app="app">

  <head>
    <script data-require="[email protected]" data-semver="1.9.0" src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.js"></script>
    <script data-require="[email protected]" data-semver="1.0.7" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js"></script>
    <script src="script.js"></script>
  </head>

  <body ng-controller="MyCtrl">
    <a ng-click="alert()">Click me</a>
  </body>

</html>

script.js

angular.module('app', [])
  .directive('ngClick', function($rootScope) {
      return {
        restrict: 'A',
        priority: 100, // give it higher priority than built-in ng-click
        link: function(scope, element, attr) {
          element.bind('click', function() {
            // do something with $rootScope here, as your question asks for that
            alert('overridden');
          })
        }
      }
  })
  .controller('MyCtrl', function($scope) {
    $scope.alert = function() {
      alert('built-in!')
    }
  })
Siphonophore answered 25/8, 2013 at 3:37 Comment(4)
Buu, can we stop first ng-click totally? i mean after running 'overridden' alert, 'built-in' not to run.Success
Don't pass an expression to ng-click, see plnkr.co/edit/uROkIcGKLspLnVsjmAKn?p=preview. If you have to pass s/t, then don't handle it, e.g. $scope.alert = function() {}.Siphonophore
this is not the correct answer, checkout the Eric Chen one below!Tutuila
Concur with JackNova, this answer is not correct. * you CAN override/replace all directives as @eric-chen shows below * this example approach will run into issues - you cannot have multiple directives on the same element requesting an isolate scope or setting a template. Eric's approach solves that tooRefit

© 2022 - 2024 — McMap. All rights reserved.