poshest
poshest

Reputation: 4237

AngularJS $watches: more simple ones or less complex ones?

Which is better for performance, readability and maintainability (Angular 1.5)?

Less, but more complex watches

// component template

<div ng-if="vm.obj.a.b + vm.stuff.c.d + vm.another.thing">
  {{ vm.obj.a.b + vm.stuff.c.d + vm.another.thing }}
</div>

Or more, but simpler watches

// component template

<div ng-if="vm.sum">
  {{ vm.sum }}
</div>

// component controller...

var vm = this;
$scope.$watch('vm.obj.a.b', fnSum);
$scope.$watch('vm.stuff.c.d', fnSum);
$scope.$watch('vm.another.thing', fnSum);

function fnSum() {
  vm.sum = vm.obj.a.b + vm.stuff.c.d + vm.another.thing;
}

Or is there a better way that I'm missing?

This is just a simplified illustration of a situation I come across a LOT. Please focus on the principle, not this exact example.

Upvotes: 2

Views: 55

Answers (2)

georgeawg
georgeawg

Reputation: 48968

For readability and maintainability invoke the function directly from the template:

<div ng-show="vm.sum = vm.fnSum()">
  {{ vm.sum }}
</div>

JS

vm.fnSum = function fnSum() {
    return vm.obj.a.b + vm.stuff.c.d + vm.another.thing;
}

Also using ng-show avoids creating a new scope.

Be aware that, under the hood, ng-if, ng-show, and {{ fn() }} all create scope watchers. Adding additional watchers for each term of an expression doesn't improve performance.

Upvotes: 2

Harris
Harris

Reputation: 1785

The latter is better for maintenance reasons:

  1. It allows you to put a succinct end-result into the view, allowing anyone scrolling through to simply read the intended output, rather than parts of what will produce the final result. The view remains uncluttered, while the controller can have verbose comments and contain the entire process for getting the ngIf determination.

  2. It abstracts a potentially volatile result. Say that you needed to change/update what actually triggered ngIf; the former would require you to change every instance in the view along with whatever controller changes you're making. The latter is simply updating how the final value came to be in the controller, and knowing that the view is already set.

You could probably make the latter a little better by refactoring it into one $watch:

var vm = this;
$scope.$watch(function(){
    return vm.obj.a.b + vm.stuff.c.d + vm.another.thing;
}, fnSum);

function fnSum(newSum, oldSum) {
  vm.sum = newSum;
}  

Upvotes: 1

Related Questions