Automatically pass $event with ng-click?

后端 未结 4 2021
别那么骄傲
别那么骄傲 2020-12-05 01:42

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

相关标签:
4条回答
  • 2020-12-05 01:54

    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.

    0 讨论(0)
  • 2020-12-05 01:58

    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

    0 讨论(0)
  • 2020-12-05 02:14

    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!

    0 讨论(0)
  • 2020-12-05 02:16

    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).

    0 讨论(0)
提交回复
热议问题