[javascript] Automatically pass $event with ng-click?

I know that I can get access to the click event from ng-click if I pass in the $event object like so:

<button ng-click="myFunction($event)">Give me the $event</button>

<script>
  function myFunction (event) {
    typeof event !== "undefined" // true
  }
</script>

It's a little bit annoying having to pass $event explicitly every time. Is it possible to set ng-click to somehow pass it to the function by default?

The answer is


Take a peek at the ng-click directive source:

...
compile: function($element, attr) {
  var fn = $parse(attr[directiveName]);
  return function(scope, element, attr) {
    element.on(lowercase(name), function(event) {
      scope.$apply(function() {
        fn(scope, {$event:event});
      });
    });
  };
}

It shows how the event object is being passed on to the ng-click expression, using $event as a name of the parameter. This is done by the $parse service, which doesn't allow for the parameters to bleed into the target scope, which means the answer is no, you can't access the $event object any other way but through the callback parameter.


I wouldn't recommend doing this, but you can override the ngClick directive to do what you are looking for. That's not saying, you should.

With the original implementation in mind:

compile: function($element, attr) {
  var fn = $parse(attr[directiveName]);
  return function(scope, element, attr) {
    element.on(lowercase(name), function(event) {
      scope.$apply(function() {
        fn(scope, {$event:event});
      });
    });
  };
}

We can do this to override it:

// Go into your config block and inject $provide.
app.config(function ($provide) {

  // Decorate the ngClick directive.
  $provide.decorator('ngClickDirective', function ($delegate) {

    // Grab the actual directive from the returned $delegate array.
    var directive = $delegate[0];

    // Stow away the original compile function of the ngClick directive.
    var origCompile = directive.compile;

    // Overwrite the original compile function.
    directive.compile = function (el, attrs) {

      // Apply the original compile function. 
      origCompile.apply(this, arguments);

      // Return a new link function with our custom behaviour.
      return function (scope, el, attrs) {

        // Get the name of the passed in function. 
        var fn = attrs.ngClick;

        el.on('click', function (event) {
          scope.$apply(function () {

            // If no property on scope matches the passed in fn, return. 
            if (!scope[fn]) {
              return;
            }

            // Throw an error if we misused the new ngClick directive.
            if (typeof scope[fn] !== 'function') {
              throw new Error('Property ' + fn + ' is not a function on ' + scope);
            }

            // Call the passed in function with the event.
            scope[fn].call(null, event);

          });
        });          
      };
    };    

    return $delegate;
  });
});

Then you'd pass in your functions like this:

<div ng-click="func"></div>

as opposed to:

<div ng-click="func()"></div>

jsBin: http://jsbin.com/piwafeke/3/edit

Like I said, I would not recommend doing this but it's a proof of concept showing you that, yes - you can in fact overwrite/extend/augment the builtin angular behaviour to fit your needs. Without having to dig all that deep into the original implementation.

Do please use it with care, if you were to decide on going down this path (it's a lot of fun though).


As others said, you can't actually strictly do what you are asking for. That said, all of the tools available to the angular framework are actually available to you as well! What that means is you can actually write your own elements and provide this feature yourself. I wrote one of these up as an example which you can see at the following plunkr (http://plnkr.co/edit/Qrz9zFjc7Ud6KQoNMEI1).

The key parts of this are that I define a "clickable" element (don't do this if you need older IE support). In code that looks like:

<clickable>
  <h1>Hello World!</h1>
</clickable>

Then I defined a directive to take this clickable element and turn it into what I want (something that automatically sets up my click event):

app.directive('clickable', function() {
    return {
        transclude: true,
        restrict: 'E',
        template: '<div ng-transclude ng-click="handleClick($event)"></div>'
    };
});

Finally in my controller I have the click event ready to go:

$scope.handleClick = function($event) {
    var i = 0;
};

Now, its worth stating that this hard codes the name of the method that handles the click event. If you wanted to eliminate this, you should be able to provide the directive with the name of your click handler and "tada" - you have an element (or attribute) that you can use and never have to inject "$event" again.

Hope that helps!


Add a $event to the ng-click, for example:

<button type="button" ng-click="saveOffer($event)" accesskey="S"></button>

Then the jQuery.Event was passed to the callback:

enter image description here


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to angularjs

AngularJs directive not updating another directive's scope ERROR in Cannot find module 'node-sass' CORS: credentials mode is 'include' CORS error :Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response WebSocket connection failed: Error during WebSocket handshake: Unexpected response code: 400 Print Html template in Angular 2 (ng-print in Angular 2) $http.get(...).success is not a function Angular 1.6.0: "Possibly unhandled rejection" error Find object by its property in array of objects with AngularJS way Error: Cannot invoke an expression whose type lacks a call signature

Examples related to angularjs-directive

Angular2 - Input Field To Accept Only Numbers Use of symbols '@', '&', '=' and '>' in custom directive's scope binding: AngularJS ng-change not working on a text input Controller not a function, got undefined, while defining controllers globally Find child element in AngularJS directive Angular directives - when and how to use compile, controller, pre-link and post-link How to validate email id in angularJs using ng-pattern Enable/Disable Anchor Tags using AngularJS get original element from ng-click How to detect browser using angularjs?

Examples related to dom-events

Detecting real time window size changes in Angular 4 Does Enter key trigger a click event? What are passive event listeners? Stop mouse event propagation React onClick function fires on render How do you Hover in ReactJS? - onMouseLeave not registered during fast hover over iFrame onload JavaScript event addEventListener, "change" and option selection Automatically pass $event with ng-click? JavaScript click event listener on class

Examples related to angularjs-ng-click

AngularJS : ng-click not working How to trigger ngClick programmatically Automatically pass $event with ng-click? adding and removing classes in angularJs using ng-click AngularJS ng-click stopPropagation Pass a reference to DOM object with ng-click Adding parameter to ng-click function inside ng-repeat doesn't seem to work How/when to use ng-click to call a route?