AngularJS - pass function to directive

Angularjs

Angularjs Problem Overview


I have a example angularJS

<div ng-controller="testCtrl">

<test color1="color1" updateFn="updateFn()"></test>
</div>
 <script>
  angular.module('dr', [])
.controller("testCtrl", function($scope) {
	$scope.color1 = "color";
	$scope.updateFn = function() {
		alert('123');
	}
})
.directive('test', function() {
	return {
		restrict: 'E',
		scope: {color1: '=',
				updateFn: '&'},
		template: "<button ng-click='updateFn()'>Click</button>",
		replace: true,
		link: function(scope, elm, attrs) {	
		}
	}
});

</script>
</body>

</html>

I want when I click button, the alert box will appear, but nothing show.

Can anyone help me?

Angularjs Solutions


Solution 1 - Angularjs

To call a controller function in parent scope from inside an isolate scope directive, use dash-separated attribute names in the HTML like the OP said.

Also if you want to send a parameter to your function, call the function by passing an object:

<test color1="color1" update-fn="updateFn(msg)"></test>

##JS##

var app = angular.module('dr', []);

app.controller("testCtrl", function($scope) {
	$scope.color1 = "color";
	$scope.updateFn = function(msg) {        
		alert(msg);
	}
});

app.directive('test', function() {
	return {
		restrict: 'E',
		scope: {
			color1: '=',
			updateFn: '&'
		},
		// object is passed while making the call
		template: "<button ng-click='updateFn({msg : \"Hello World!\"})'>
			Click</button>",
		replace: true,        
		link: function(scope, elm, attrs) {             
		}
	}
});

Fiddle

Solution 2 - Angularjs

Perhaps I am missing something, but although the other solutions do call the parent scope function there is no ability to pass arguments from directive code, this is because the update-fn is calling updateFn() with fixed parameters, in for example {msg: "Hello World"}. A slight change allows the directive to pass arguments, which I would think is far more useful.

<test color1="color1" update-fn="updateFn"></test>

Note the HTML is passing a function reference, i.e., without () brackets.

JS

var app = angular.module('dr', []);

app.controller("testCtrl", function($scope) {
    $scope.color1 = "color";
    $scope.updateFn = function(msg) {        
        alert(msg);
    }
});

app.directive('test', function() {
    return {
        restrict: 'E',
        scope: {
            color1: '=',
            updateFn: '&'
        },
        // object is passed while making the call
        template: "<button ng-click='callUpdate()'>
            Click</button>",
        replace: true,        
        link: function(scope, elm, attrs) {       
          scope.callUpdate = function() {
            scope.updateFn()("Directive Args");
          }
        }
    }
});

So in the above, the HTML is calling local scope callUpdate function, which then 'fetches' the updateFn from the parent scope and calls the returned function with parameters that the directive can generate.

http://jsfiddle.net/mygknek2/

Solution 3 - Angularjs

In your 'test' directive Html tag, the attribute name of the function should not be camelCased, but dash-based.

so - instead of :

<test color1="color1" updateFn="updateFn()"></test>

write:

<test color1="color1" update-fn="updateFn()"></test>

This is angular's way to tell the difference between directive attributes (such as update-fn function) and functions.

Solution 4 - Angularjs

How about passing the controller function with bidirectional binding? Then you can use it in the directive exactly the same way as in a regular template (I stripped irrelevant parts for simplicity):

<div ng-controller="testCtrl">
   
   <!-- pass the function with no arguments -->
   <test color1="color1" update-fn="updateFn"></test>
</div>

<script>
   angular.module('dr', [])
   .controller("testCtrl", function($scope) {
      $scope.updateFn = function(msg) {
         alert(msg);
      }
   })
   .directive('test', function() {
      return {
         scope: {
            updateFn: '=' // '=' bidirectional binding
         },
         template: "<button ng-click='updateFn(1337)'>Click</button>"
      }
   });
</script>

I landed at this question, because I tried the method above befire, but somehow it didn't work. Now it works perfectly.

Solution 5 - Angularjs

use dash and lower case for attribute name ( like other answers said ) :

 <test color1="color1" update-fn="updateFn()"></test>

And use "=" instead of "&" in directive scope:

 scope: { updateFn: '='}

Then you can use updateFn like any other function:

 <button ng-click='updateFn()'>Click</button>

There you go!

Solution 6 - Angularjs

I had to use the "=" binding instead of "&" because that was not working. Strange behavior.

Solution 7 - Angularjs

@JorgeGRC Thanks for your answer. One thing though, the "maybe" part is very important. If you do have parameter(s), you must include it/them on your template as well and be sure to specify your locals e.g. updateFn({msg: "Directive Args"}.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser2707026View Question on Stackoverflow
Solution 1 - AngularjsAlwaysALearnerView Answer on Stackoverflow
Solution 2 - AngularjssteveView Answer on Stackoverflow
Solution 3 - AngularjsOfer SegevView Answer on Stackoverflow
Solution 4 - AngularjsMárton TamásView Answer on Stackoverflow
Solution 5 - AngularjsJaneView Answer on Stackoverflow
Solution 6 - AngularjsGunter ReinitzerView Answer on Stackoverflow
Solution 7 - Angularjsuser2893858View Answer on Stackoverflow