I made a directive designed to be attached to an element using the ngModel directive. If the model\'s value matches something the value should then set to the previous valu
Our best guess here is that setting old == new prevents a dirty check from happening
A watcher listener is only called when the value of the expression it's listening to changes. But since you changed the model back to its previous value, it won't get called again because it's like the value hasn't changed at all. But, be careful: changing the value of a property inside a watcher monitoring that same property can lead to an infinite loop.
However it won't update the DOM (and what you see in the browser) until I explicitly call ngModel.$render() after setting the new value.
That's correct. $setViewValue
sets the model value as if it was updated by the view, but you need to call $render
to effectively render the view based on the (new) model value. Check out this discussion for more information.
Finally, I think you should approach your problem a different way. You could use the $parsers
property of NgModelController
to validate the user input, instead of using a watcher:
link: function (scope, element, attrs, ngModel) {
if (!ngModel) return;
ngModel.$parsers.unshift(function(viewValue) {
if(viewValue === 'foo') {
var currentValue = ngModel.$modelValue;
ngModel.$setViewValue(currentValue);
ngModel.$render();
return currentValue;
}
else
return viewValue;
});
}
I changed your jsFiddle script to use the code above.
angular.module('myDirective', [])
.directive('myDirective', function () {
return {
restrict: 'A',
terminal: true,
require: "?ngModel",
link: function (scope, element, attrs, ngModel) {
if (!ngModel) return;
ngModel.$parsers.unshift(function(viewValue) {
if(viewValue === 'foo') {
var currentValue = ngModel.$modelValue;
ngModel.$setViewValue(currentValue);
ngModel.$render();
return currentValue;
}
else
return viewValue;
});
}
};
});
function x($scope) {
$scope.test = 'value here';
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<h1>Foo Fighter</h1>
I hate "foo", just try and type it in the box.
<div ng-app="myDirective" ng-controller="x">
<input type="text" ng-model="test" my-directive>
<br />
model: {{test}}
</div>