how to use a model property as variable ng-click
Asked Answered
I

4

5

I'd like to have function calls for ng-click stored as strings in my model. I can't use ng-click="m.func", and if i'm using ng-click="{{m.func}}" ist also not working.

http://jsfiddle.net/j8wW5/19/

It also looks like angular 1.2.0 throws an error in case of ng-click="{{m.func}}".

How can I bring it to work?

<div ng-app="myApp" ng-controller="myCtrl">
    <div ng-repeat="m in model"><a href="#" ng-click="{{m.func}}">{{m.caption}}</a></div>
</div>

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

app.controller('myCtrl', function($scope) {
    $scope.model = [
        {
            caption: 'callme a',
            func : 'callme_a()'
        },
        {
            caption: 'callme b',
            func : 'callme_b()'
        }
    ]

    $scope.callme_a = function() {
        alert("called a");
    }

    $scope.callme_b = function() {
        alert("called b");
    }
});
Iredale answered 12/11, 2013 at 13:23 Comment(0)
B
0

It could be that ng-click is attaching an event listener to the dom with the ng-click attribute before it's evaluated to a string.

So, I've overridden the ngclick with a timeout to make what you want work :)

var app = angular.module('myApp', []); 
app.directive('ngClick', ['$timeout','$parse', function($timeout, $parse) {
          return {
              compile: function($element, attr) {
                  return function(scope, element, attr) {
                      //I've wrapped this link function code in a $timeout
                      $timeout(function() {
                          var fn = $parse(attr["ngClick"]);
                          $(element[0]).on("click", function(event) {
                              scope.$apply(function() {
                                  fn(scope, {$event:event});
                              });
                          });
                      })
                  };
              }
          };
      }]);

(Here is the source code for ngClick - https://github.com/angular/angular.js/blob/master/src/ng/directive/ngEventDirs.js)

Check the fiddle here with the demo - http://jsfiddle.net/R2Cc9/5/

Blanton answered 13/11, 2013 at 18:27 Comment(0)
A
8

You can do something like this:

In your html:

<div ng-repeat="m in model"><a href="#" ng-click="call(m)">{{m.caption}}</a></div>

In your controller:

$scope.callme_a = function() {
    alert("called a");
}

$scope.callme_b = function() {
    alert("called b");
}

$scope.model = [
    {
        caption: 'callme a',
        func : $scope.callme_a
    },
    {
        caption: 'callme b',
        func : $scope.callme_b
    }
]

$scope.call = function(el) {
    el.func();   
}

Fiddle

Attach answered 12/11, 2013 at 13:31 Comment(2)
OK, I see. But I have "real" strings for the function names (model is filled a result from a database request). Any other way?Iredale
Yes! If func is a string (even if it has arguments), in $scope.call you can do: $scope.$eval(el.func); instead of el.func(); Pair this up with $interpolate to support {{...}} expressions in your func string, and you've got some pretty cool stuff going on.Iconoclasm
B
1

You can use

window["functionName"](arguments) //if the functioName is defined in global (window's scope)

OR

$scope["functionName"](arguments) //if the functioName is defined for $scope 

So, updated controller code (of Beterraba) would be

callme_a = function() {
    alert("called a");
}

callme_b = function() {
    alert("called b");
}

$scope.model = [
    {
        caption: 'callme a',
        func : "callme_a"
    },
    {
        caption: 'callme b',
        func : "callme_b"
    }
]

$scope.call = function(el) {
   window[el.func](arguments)
}
Blanton answered 12/11, 2013 at 14:16 Comment(0)
A
1

This is a variation on @Beterraba's answer.

Here is the fiddle.

HTML:

<div ng-app="myApp" ng-controller="myCtrl">
    <div ng-repeat="m in model"><a href="#" ng-click="call(m.func)">{{m.caption}}</a></div>
</div>

JS:

$scope.call = function(func) {
    $scope[func]();
}

If you have to use strings to define the functions then this will work. But I would urge you to look again at your design.

Also, in order for this to work, you must take out the () in the function string:

$scope.model = [
    {
        caption: 'callme a',
        func : 'callme_a'
    },
    {
        caption: 'callme b',
        func : 'callme_b'
    }
]
Awed answered 12/11, 2013 at 14:20 Comment(4)
That works, but is there no way to use the string in model as input for ng-click directly? Wouldn't it be possible to put html in a template and to compile it somehow? Imagine, if you have to call the function with parameters, you can't take away the ().Iredale
If you have the arguments evaluated, then you can probably use "eval" but people won't recommend using it. As long as it's safe for you, you can go ahead and use it - here is the update fiddle - jsfiddle.net/R2Cc9/2Blanton
OK, that is an option. I tryed to avoid eval, if possible. I agree, it is working at least. But I wonder why the expression in {{}} is not executed. Do you have a short explation for this behaviour? If I'm inspecting the html, the source looks like ng-click='callme_a("parameter")' - and if I hardcode this, I can see no difference. One is working and the other one is not.Iredale
It could be that ng-click is attaching event listener to the dom with the ng-click attribute before it's evaluated to a string. I've added another answer with a fiddle link by modifying the ngClickBlanton
B
0

It could be that ng-click is attaching an event listener to the dom with the ng-click attribute before it's evaluated to a string.

So, I've overridden the ngclick with a timeout to make what you want work :)

var app = angular.module('myApp', []); 
app.directive('ngClick', ['$timeout','$parse', function($timeout, $parse) {
          return {
              compile: function($element, attr) {
                  return function(scope, element, attr) {
                      //I've wrapped this link function code in a $timeout
                      $timeout(function() {
                          var fn = $parse(attr["ngClick"]);
                          $(element[0]).on("click", function(event) {
                              scope.$apply(function() {
                                  fn(scope, {$event:event});
                              });
                          });
                      })
                  };
              }
          };
      }]);

(Here is the source code for ngClick - https://github.com/angular/angular.js/blob/master/src/ng/directive/ngEventDirs.js)

Check the fiddle here with the demo - http://jsfiddle.net/R2Cc9/5/

Blanton answered 13/11, 2013 at 18:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.