If this is already explained or discussed somewhere, I am very sorry, but I couldn't find this exact problem discussed anywhere.
So I have an angular directive with one data binding 'myvar' (= or @ makes no difference). The value from the data binding is used in the directive: scope.myvarStr = scope.myvar + 'somestring'. Then I bind myvarStr in the template.
Because scope.myvarStr must be modified when scope.myvar changes, I used $watch('myvar', function(...)) to watch the value and update scope.myVarStr when needed. In the watch function I put the classic if (newValue === oldValue) return;
The problems started the very first time $watch fired and the two values were equal; then the view was not updated. I could easily see that from console.log(scope.myvar) on the first line in the link function that scope.myvar was undefined (or '' dependent on binding type) to begin with and that the value had changed to something else when I did a console.log in the $watch.
I googled for an hour or so, and found this: https://github.com/angular/angular.js/issues/11565 However, this issue wasn't discussed anywhere else, so I looked googled more and came across $observe AngularJS : Difference between the $observe and $watch methods
When I changed from $watch to $observe, all my problems went away and I can still use if(newValue === oldValue) return;.
(function(directives) {
'use strict';
directives.directive('someDir', [function() {
return {
restrict: 'E',
scope: {
myvar: '=' //or @ didn't matter at the time...
},
template: '<p>{{myvarStr}}</p>',
link: function(scope, el, attrs) {
function toString() {
if (scope.myvar < 1000) {
scope.myvarStr = scope.myvar;
} else {
scope.myvarStr = scope.myvar/1000 + 'k';
}
}
toString();
scope.$watch('myvar', function(newValue, oldValue) {
console.log("changed", newValue, oldValue)
if (newValue == oldValue) return;
toString();
},true);
// When changing to $observe it works :)
//attrs.$observe('myvar', function(newValue, oldValue) {
// console.log("changed", newValue, oldValue)
// if (newValue == oldValue) return;
// toString();
//},true);
}
};
}]);
}(angular.module('myApp.directives')));
Suggestion: As far as I understand this issue occurs with $watch because the scope value is never changed. It takes a while for the directive to pick up the value, until then the binding is just an empty string or something and when the value is detected the $watch fires but the actual scope value has not changed (or as explained in the first link; the first watch fires when the value 'appears' in the directive).