10

I have this code inside an angular directive, and I'm finding the $watch behavior a bit confusing. The updateSelect is called in an "ng-click":

scope.updateSelect = function (type) {
    scope.selectionCtrl.activeList = scope.seedLists[type]; 
    scope.selectionCtrl.activeListKey = type; 
    scope.selectionCtrl.activeSelection = scope.selection[type];
    scope.selectionCtrl.staged = [];
    scope.selectionCtrl.stageRemove = [];
    if (type !== scope.activeTab) {
        scope.activeTab = type;
    }
    console.log("update");
};

scope.$watch('selectionCtrl.activeList', function(newValue, oldValue) {
    console.log("watch");
}, true);

When I click on the button (triggering updateSelect), and watch the console, I see "update" and then "watch". The first thing that happens inside the function is selectionCtrl.activeList is set, so I would expect to see "watch" and then "update".

Shouldn't watch trigger as soon as the array has changed?

Doug Molineux
  • 12,283
  • 25
  • 92
  • 144

3 Answers3

2

The function has to finish first as javascript is single threaded.

Because the function was called via the ng-click directive, angular will run a digest cycle. Part of that digest cycle is to run through the watch list and resolve all the changes that may have occurred since the cycle last ran.

In the example you give, selectionCtrl.activeList is changed in updateSelect which subsequently results in the watch callback being called.

Gruff Bunny
  • 27,738
  • 10
  • 72
  • 59
1

When does Angular execute watch callback?

It's related to $digest and $apply, and certainly it does not execute within your raw javascript code.

To make watch execute forcefully, you can run $scope.apply() manually, but may cause more problem and not necessary if it is within a angularjs function, i.e. $timeout, $interval, etc, because it will be called automatically after the function.

For more info., lookup;

Community
  • 1
  • 1
allenhwkim
  • 27,270
  • 18
  • 89
  • 122
-1

https://docs.angularjs.org/api/ng/type/$rootScope.Scope :

The watchExpression is called on every call to $digest() and should return the value that will be watched. (Since $digest() reruns when it detects changes the watchExpression can execute multiple times per $digest() and should be idempotent.)

If you try i.e.:

scope.selectionCtrl.activeList = scope.seedLists[type]; 
scope.$digest();

you'll get Error: [$rootScope:inprog] $apply already in progress.

Petr Averyanov
  • 9,327
  • 3
  • 20
  • 38