user1563700
user1563700

Reputation:

Angularjs reuse calculated values

I need to use a calculated value to hide elements and do other things in the template.

<button ng-hide="expensive()" ng-click="foo()">foo</button>
<button ng-show="expensive() && otherFunction()" ng-click="bar()">bar</button>
<span ng-show="expensive()">Bas</span>

This causes the excecution of expensive() multiple times for each $digest cycle. I want to reuse its result, but it needs to be executed for each digest - just not multiple times per digest.

Is there any best practice for reuse function results that needs to be re-calculated each digest?

* update * This function works with a huge object and its properties can be changed with a lot of input fields and sub-formulars on the page. It has multiple one to many relations. If I have to add events / ngChanges to each field and if I miss only one, this will not work correcly.

Upvotes: 3

Views: 585

Answers (3)

Ben Lesh
Ben Lesh

Reputation: 108491

You didn't really give us enough information to give you the best option for your situation.

Very generally speaking, the best option is to have whatever interactions that cause the return value of expensive() to change update a $scope.property and just use that in your view.

In other words, don't use functions on scope in your view unless you're setting up a binding like ng-click or something. Instead, update properties on your scope whenever they need updating and just reference them directly.

Caution: This might tempt you to use $watch... don't do that. There are cheaper, more effective ways to trigger updates, like ngChange, or other such events.

Upvotes: 2

Zack Argyle
Zack Argyle

Reputation: 8407

Try this.

<button ng-hide="result" ng-click="foo()">foo</button>
<button ng-show="result && otherFunction()" ng-click="bar()">bar</button>
<span ng-show="expensive()">Bas</span>

Controller:

$scope.expensive = function() {
    ... do stuff ...
    $scope.result = ...;
    return $scope.result;
}

Upvotes: 0

Jonathan Rowny
Jonathan Rowny

Reputation: 7588

You have a few options:

  1. make expensive() a $q promise. Angular templates understand $q promises and resolve them accordingly
  2. store the value when running the function, if the value exists return it first thing in the function. You can add a flush param to it in case you want to flush the cached value.
  3. If the values truly never change once computed, you could put them in a resolve
  4. If these values are the result of some DOM work, create a directive to do this and $emit actual changes to the parent scope.

Upvotes: 1

Related Questions