Emil Devantie Brockdorff
Emil Devantie Brockdorff

Reputation: 4954

AngularJS: Function in controller called multiple times by template

I know this question has been asked in here before it seem that all the answers is either quotes from AngularJS doc or doesn't provide with a solution (not a solution I understand anyway) so I'll give it a try once more.

My experience with Angular is relatively new, started out some month ago, so please forgive my ignorance if this is basic knowledge.

Within a list of posts (iterate by using ng-repeat) I've a special "share to" button.
The link on the button (href) depends on three different factors: post_id, user_id, network.

I'm trying to do this, within my ng-repeat="post in posts"

<a href ng-href="{{genShareUrl(post.id,post.author_id,'fb')}}>Facebook</a>

The original function which perform the generation is in a factory, I just use genShareUrl as a middleman function between controller and factory.

When logging out from the genShareUrl function in the post controller, I see this function is called multiple times.
Actually, if I run it on full scale on all posts fetched from backend, my app just come to a halt. No error, just eternal loading (I figured that I might have inadvertently triggered some kind of eternally $digest loop I'm unfamiliar with or at least some exponentially call pattern).

I've tried to recreate the scenario with a simple example:
http://codepen.io/Mestika/pen/xVexRa

Here I can see, that the function first is called twice, then four times - which indicates to me that the digest cycle is triggered multiple time.

In such a case as described, how would I best go about generating some value in a link? Is this the best practice? If no, how or could you give me an example on how to refactor the code.

Upvotes: 2

Views: 1005

Answers (2)

luixaviles
luixaviles

Reputation: 689

I'd like suggest a best practice for your case:

Resolve start-up logic for a controller in an activate function.

So, you can add an activate function as follows:

activate();

function activate() {
    angular.forEach($scope.json, function (p) {
        p.btoa = $scope.func(p.id);
    });
}

After that, you can update your template and use:

<div ng-repeat="person in json">
    <a href ng-href="/user/{{person.btoa}}">{{person.firstName + ' ' + person.lastName}}</a>    
  </div>

In that way you'll avoid multiple calls to your function due to two-way data binding behavior.

Take a look following links:

Upvotes: 0

MarkoCen
MarkoCen

Reputation: 2324

Angular uses dirty checking to achieve two-way binding, all two-way binding watchers would be evaluated in each digest cycle, that is the reason genShareUrl be called multiple times, to avoid this happened, you could use one-way binding in your template:

<a href ng-href="{{::genShareUrl(post.id,post.author_id,'fb')}}>Facebook</a>

Upvotes: 1

Related Questions