AngularJS directive binding a function with multiple arguments

68,093

Solution 1

There is one small mistake in your code, please try the code below and it should work for you

<!doctype html>
<html ng-app="test">
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.js"></script>

  </head>
 <body ng-controller="test" >    


<!-- tabs -->
<div my-directive on-drop="handleDrop(elementId,file)"></div>

 <script>
     var app = angular.module('test', []);

     app.directive('myDirective', function () {
         return {
             scope: {
                 onDrop: '&'
             },
             link: function (scope, elem, attrs) {
                 var elementId = 123;
                 var file = 124;
                 scope.onDrop({elementId:'123',file:'125'});

             }
         }
     });

     app.controller('test', function ($scope) {
         alert("inside test");
         $scope.handleDrop = function (elementId, file) {
             alert(file);
         }
     });

   </script>
</body>


</html>

Solution 2

Alternative method that will survive minification

Leave your html as it was:

<my-directive on-drop="handleDrop"></my-directive>

Change the call to:

scope.onDrop()('123','125')

Notice the extra opening and closing parenthesis given to onDrop. This will instantiate the function instead of injecting the function's code.

Why is it better

  1. Changing the parameters' names in the handleDrop() definition (or even adding some more, if you handle it correctly) will not make you change each of the directives injections in the html. much DRYer.

  2. As @TrueWill suggested, I'm almost sure the other solutions will not survive minification, while this way code stays with maximum flexibility and is name agnostic.

Another personal reason is the object syntax, which makes me write much more code:

functionName({xName: x, yName: y}) // (and adding the function signature in every directive call)

As opposed to

functionName()(x,y) // (zero maintenance to your html)

I found this great solution here.

Share:
68,093
Joseph Paterson
Author by

Joseph Paterson

Updated on July 22, 2022

Comments

  • Joseph Paterson
    Joseph Paterson almost 2 years

    I'm having some trouble binding a function defined in a controller with a callback function in a directive. My code looks like the following:

    In my controller:

    $scope.handleDrop = function ( elementId, file ) {
        console.log( 'handleDrop called' );
    }
    

    Then my directive:

    .directive( 'myDirective', function () {
        return {
          scope: {
            onDrop: '&'
          },
          link: function(scope, elem, attrs) {
            var myFile, elemId = [...]
    
            scope.onDrop(elemId, myFile);
          }
        } );
    

    And in my html page:

    <my-directive on-drop="handleDrop"></my-directive>
    

    Having no luck with the code above. From what I've read in various tutorials I understand I'm supposed to specify the arguments in the HTML page?

  • Nick Radford
    Nick Radford over 10 years
    Where is this behavior defined in the Angular documentation?
  • tommybananas
    tommybananas over 10 years
    There doesn't seem to be an actual topic in the docs but the topic is the linking function of directives, docs.angularjs.org/guide/directive
  • TrueWill
    TrueWill about 10 years
    Apparently the parameter names have to match the markup exactly; I wonder if this would survive minification?
  • Joseph Paterson
    Joseph Paterson almost 10 years
    @TrueWill I think AngularJS struggles with traditional minification altogether, but it does have an ngmin module that does the same thing
  • TrueWill
    TrueWill almost 10 years
    @JosephPaterson According to the web page ngmin is deprecated in favor of ng-annotate. Thanks!
  • Justin Boyson
    Justin Boyson almost 8 years
    This worked for me as well, but I had an issue using object notation. Explicitly using classes in Typescript. this comment helped me fix it.
  • Collin Thomas
    Collin Thomas almost 6 years
    This works. I was getting "TypeError: Cannot use 'in' operator to search for x in y" by doing what the Joe was.