简体   繁体   中英

Call Angular function in controller and pass result to directive

I am having a problem with Angular's digest cycle going crazy:

angular.js:12330 Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!

I have this custom Directive:

<b-bar-chart b-data="getData(question)"></b-bar-chart>

in Which, the getData function calls a function in the controller (NOT IN THE DIRECTIVE so using & instead of = in the directive for one way binding does not work). Controller function:

$scope.getData = function (question) {
    return [
      {
        'name': 'Strongly Agree',
        'value': question.stats.responsePercentages.stronglyagree
      },
      {
        'name': 'Agree',
        'value': question.stats.responsePercentages.agree
      }
    ]
  }

In the Directive I have this:

scope: {
    // I think this should this be = and not &, because the function is in the controller and not in the directive
    data: '=bData'
},

And in the directive template I have this:

<li ng-repeat="d in data">
    <div class="percent">{{d.value|number:0}}<span>%</span></div>
    <div class="fm-bar-text">{{d.name}}</div>
</li>

It looks like it continues to call the code in the controller which causes unnecessary loops. Is there a way to make sure the getData function is called only once, or is there a different solution? Thanks

getData should not return a new array, otherwise Angular assumes the data is new. You should assign the result to $scope and bind it that way. Its generally best to avoid function calls when binding.

Instead of computing getData(question) every digest cycle, refactor to compute it only when question changes:

Parent Controller:

 $scope.$watch("question", function(newValue) {
     $scope.bData = $scope.getData(newValue);
 });

HTML:

 <!-- Re-factor this -->
 <b-bar-chart b-data="getData(question)"></b-bar-chart>

 <!-- TO this -->
 <b-bar-chart b-data="bData"></b-bar-chart>

So instead of computing the array every digest cycle, a new array is created only when the question changes.

In directive = used for two way binding between scope variables. In your directive you are binding it to a function return value which will be considered as a new value every time and digest process will take place continuously.

I would suggest to call the function inside directive and assign it to a scope variable.

Check out Working Fiddle .

Directive:

MyApp.directive("bBarChart", function($compile){
    return {
      restrict: "E",
    scope: {
      data: '&bData'
    },
    template: '<li ng-repeat="d in data_values">' +
      '<div class="percent">{{d.value|number:0}}<span>%</span></div>' +
      '<div class="fm-bar-text">{{d.name}}</div>' +
        '</li>',
    link: function(s, e, a){
        s.data_values = s.data();
    }
  }
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM