2

I would like to assign different functions to ng-click within ng-repeat:

<button ng-repeat="button in notification.buttons" ng-click="button.fn"> {{button.label}} </button>

Controllers:

app.controller('MainCtrl', ['$scope', function($scope){
    $scope.notification = {
        ctrl: 'logout', 
        text: 'Logout?',
        buttons: [
                {label:'Yes', fn: 'logout()'},
                {label:'No', fn: 'cancel()'},
        ],
    };
}]);

app.controller('logout', ['$scope', function($scope){
    $scope.logout = function(){
        alert('logout');
    };
    $scope.cancel = function(){
        alert('cancel');
    };
}]);

If I put button.fn in double curlies ng-click="{{button.fn}}" the generated html looks good in the Chrome inspector, but Angular throws the following error:

Error: [$parse:syntax] Syntax Error: Token 'button.fn' is unexpected, expecting [:] at column 3 of the expression [{{button.fn}}] starting at [button.fn}}].

If there are no double curlies, no error, but Angular generates the html like this and the functions won't fire:

 <button ng-repeat="button in notification.buttons" ng-click="button.fn" class="ng-binding ng-scope"> Yes logout()</button>

PLUNKER

I have a related question about setting ng-controller with scope variables with this very same example here.

1
  • ng-click is expecting a function (IE button.fn()) not a pointer which is what you are getting. That's why it won't fire. The only option I have seen involves creating a directive. See This. Commented Oct 16, 2014 at 17:20

1 Answer 1

4

http://plnkr.co/edit/QE50kpfBjXy2WPvjVsJc?p=preview

I've created a fork of your code. Your 'fn' reference were strings. I changed them to functions, and added '()' to the 'button.fn' in the template. I also changed where the function references were made since the definitions of the functions were in a different controller.

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

app.controller('MainCtrl', ['$scope', function($scope){
    $scope.notification = {
        ctrl: 'logout', 
        text: 'Logout?',
        buttons: [
    			{label:'Yes', fn: null},
    			{label:'No', fn: null},
        ],
    };
}]);

app.directive('notification', [
	function() {
		return {
		restrict: 'E', // E = Element, A = Attribute, C = Class, M = coMment
		templateUrl: 'notification.tpl.html',
		replace: true,
		link: function(scope, element, attrs) {
      //...
		}
	};
		
		
}])

app.controller('logout', ['$scope', function($scope){
  $scope.logout = function(){
      alert('logout');
  };
  $scope.cancel = function(){
      alert('cancel');
  };
  
  $scope.notification.buttons[0].fn = $scope.logout;
  $scope.notification.buttons[1].fn = $scope.cancel;
}]);
<div ng-controller="logout">
    <p>{{notification.text}}</p>
    <button ng-repeat="button in notification.buttons" ng-click="button.fn()"> {{button.label}} {{button.fn}}</button>
    <button ng-click="logout()"> Test</button>
</div>

Sign up to request clarification or add additional context in comments.

4 Comments

Umm.. I see that you moved the functions into the main controller. Actually this is only half of the solution, because I would like to call the functions from the inner (logout) controller...
Can you update your answer to call the functions in the original controller?
The references in MainCtrl controller to logout() and cancel() are defined in the logout controller. That's a problem. MainCtrl will never know about what is defined deeper into the hierarchy. I will have to let the login controller set the function references in the buttons array to make that work. Here's a new plunkr. plnkr.co/edit/QE50kpfBjXy2WPvjVsJc?p=preview
Yes, I've been digging deeper in parent and child scope hierarchy. This is a really interesting way of solving it, thank you for sharing!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.