How to eval an attribute as string which is a cust

2019-09-19 00:15发布

问题:

I'm using Angular 1.5. I created a menu which is a component. The menu component accept as attribute a list of jsonObject to create each menuitem.

<comp-menu items="menuitems" ></comp-menu>

A menuitem is a component as well. I would like to add an attribute like "action" which would be a custom function as an evaluated string in data-ng-click... of this kind :

<comp-menuitem data-ng-repeat="item in items" data-ng-click="eval({{item.action}})"></comp-menuitem>    

The data can be like in my MainController :

$scope.menuitems = [ { label: 'menuitem 1', action: 'alert("test");'} ... ];

Anyone has an idea to make it work ?

回答1:

ng-click="evaluateAction(item.action)" where $scope.evaluateAction = eval. However using eval is rarely a good idea, you could use $eval instead, it only supports Angular expressions and it's also applied against a scope.

So you could have { action: 'openDialog(item.label)' } instead and then use it with ng-click="evaluateAction(item.action, item)" where $scope.evaluateAction = (action, item) => $eval(action, item).

Which still isn't the nicest solution, but at least it keeps your functions in an Angular context and makes it so you need to work with Angular rather than subverting it.



回答2:

The solution was almost as Scott said. $eval in a component doesn't work, even $rootScope.$eval so I used the function eval() and in the controller I bind my custom function to the $rootScope to be executed in menuitem component.

1) In menuitem.html (menuitem component) -> add data-ng-click="$ctrl.evaluateAction()"

<button data-ng-click="$ctrl.evaluateAction()"></button>

2) In the component controler (menuitem.js) -> add evaluateAction()

function menuitemController($rootScope, $scope, $element, $attrs) {
    var ctrl = this;
    ...
    ctrl.evaluateAction  = function(){
        eval(ctrl.action);
    }
}
angular.module('app')
    .component('appMenuitem', {
      transclude: false,
      controller: menuitemController,
      bindings :{
        label : '@',
        ...
        action: '@'
      },
      templateUrl: 'angular/components/menuitem/menuitem.html'
    });

3) In menu.html (Menu Component) add the action attribute

<comp-menuitem data-ng-repeat="item in items" action="{{ item.action }}"></comp-menuitem> 

4) In the main controller - add the custom function as $rootScope.openDialog()...

angular.module('app')
    .controller('MainController', ['$rootScope', '$scope', function($rootScope, $scope){
           $rootScope.openDialog = function(key){
                if(key === 'open'){
                    alert("open");
                }
            };
   ...

5) Add the action attribute data in the JSON

{ label : "foo" , action: "$rootScope.openDialog('open')"}

And it works !!!!