Don't rely on $watch oldValue newValue to initialize changes
TLDR: When you add $watch is added to your code, it runs for the first time, showing you that oldValue === newValue.
This is NOT a bug. Although it may be mistaken as one, as I first encountered it. See described.
Consider the following code. There is a portion of HTML we wish to toggle (show or hide) based on a controller property.
<!-- page.html -->
<div class="div" ng-if="ctrl.toggleShow">
<!-- some content that you wish to hide first ... -->
</div>
So far so good. Here’s the JS.
//controller.js
function MyController($scope, MyService) {
var vm = this;
vm.toggleShow = false;
$scope.$watch( function () {
return MyService.id;
}, function (newValue, oldValue) {
vm.toggleShow = true;
console.log('The old value is' + oldValue);
console.log('The new value is' + newValue);
console.log('Is old value equals to new value? :' + (oldValue === newValue));
});
}
What you will realise is that upon loading, toggleShow
will be set to true. The scary part is that MyService.id
never changed. Your console statements will tell you that oldValue
is indeed equals to newValue
.
Instead, you can try to modify your code this way, by setting a default value for MyService.id
, for instance to the string “abc”. And only watch for changes away from this value.
Like so:
//controller.js
function MyController($scope, MyService) {
var vm = this;
vm.toggleShow = false;
$scope.$watch( function () {
return MyService.id; // this will default to "abc"
}, function (newValue, oldValue) {
if (newValue === "abc") {
return
}
vm.toggleShow = true;
});
}
Hope this helps!