3

http://jsfiddle.net/V9sYB/50/

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.min.js"></script>
<div ng-app>
  <div ng-controller="SomeCtrl">
      <input ng-model="textProperty"/>      
      <span>{{computedProperty()}}</span> 
  </div>
</div>

script

function SomeCtrl($scope) {
  $scope.textProperty = "initial";
    var times = 0;
    $scope.computedProperty = function(){
        console.log(++times);
        return $scope.textProperty+ " asdf";
    };
}

Is there way to avoid/workaround Angularjs computed property running twice everytime?

or Do I have to write directive for the one that I will never reuse on another controller?

YOU
  • 120,166
  • 34
  • 186
  • 219

2 Answers2

3

When you use interpolation with {{, you are effectively creating a watch on the expression inside it. Since angularjs works on the dirty check principal, where it revaluates the expression multiple time during a digest cycle you cannot control how many times any expression defined inside a interpolation runs.

Therefore such computed property\method should have no side affects as it gets called multiple times which you as a developer do not have control.

Chandermani
  • 42,589
  • 12
  • 85
  • 88
1

If view expression is computationally expensive, it's advised to use some sort of function caching mechanism, to reduce the cost.

Your function, for example, can be easily cached using a hefty memoization method from the underscore utility belt:

FIDDLE

function SomeCtrl($scope) {
  $scope.textProperty = "initial";
  var memoizedTimes = 0;
  $scope.computedMemoizedProperty = _.memoize(function(){
    console.log(++memoizedTimes);
    return $scope.textProperty + " asdf";
  }); 
}

This ensures that function logic will always be execute at most once for every input.

Stewie
  • 60,366
  • 20
  • 146
  • 113
  • thats interesting way – YOU Jan 02 '14 at 10:35
  • hmmm, but I need to pass variables like `computedMemoizedProperty(textProperty)`, If I have 4,5 variables used in the function, might need to pass all as arguments. but its a workaround. – YOU Jan 02 '14 at 10:52
  • 1
    Take a look at _.memoize docs. It takes two functions as parameters. The first function is your actual function that you want to cache. The second function is used internally, to produce a unique identifier, which is used for caching purposes. This second function will be injected by the same parameters that are injected into your first function, but you can actually use your $scope variables in there, so there's no really a need to pass in anything. Everything is already available to you by scope inheritance. – Stewie Jan 02 '14 at 10:58
  • ok, so its a customizable, but looks like better not to do that on every calculated functions. – YOU Jan 02 '14 at 11:05