Dejan
Dejan

Reputation: 10373

Why does binding trigger a $watch although no data was changed?

I have an entity in the scope that is being edited by the user. Each time it gets modified, I want to trigger some custom validation. So I have:

// validate the position if anything has changed
$scope.$watch("entity", function() {
    if ($scope.entity.Id) {
        $scope.validate();
    }
}, true /* watch "by value" (see: https://docs.angularjs.org/guide/scope#scope-life-cycle) */);

So far so good. Now, since this is a big entity with quite some fields, not all of the fields participate initially in data-binding. Only portions of the fields are visible to the user by using a tab control. When the user switches tabs, another portion of the entity is shown.

However, when the additional controls get bound to the corresponding fields of the entity, the $watch gets triggered even though the binding doesn't change any value on the entity.

Why is this the case and how could I prevent it?

Note: I thought that the data-binding is possibly adding some internal $... fields to entity but these are hopefully disregarded (at least this is the case in angular.equals so they should probably be disregarded in the $watch too, I assume).

Upvotes: 1

Views: 49

Answers (1)

Miles P
Miles P

Reputation: 710

$watch with object equality flag true compares the properties of the old object copy with the current object. Therefore the listener fires when a property name is changed, added, or removed. You can try something like the following:

$scope.$watch("entity", function(newVal, oldVal) {
    if(Object.keys(newVal).length !== Object.keys(oldVal).length)
        return; //Detect added properties

    if ($scope.entity.Id) {
            $scope.validate();
    }
}, true

Upvotes: 1

Related Questions