Есть ли в Angular способ реагировать на изменения модели без использования $watch?
Я реализую простое управление вращением в AngularJS, и я хочу реагировать как на пользовательский ввод, так и на изменения с помощью кнопок +/-. Вот мой HTML:
<input type='button' ng-click="MyProperty = MyProperty - 1" value="-">
<input type='text' ng-model="MyProperty" ng-change="log('changed from ngChange')">
<input type='button' ng-click="MyProperty = MyProperty + 1" value="+">
Но это будет отслеживать только "пользовательские изменения", насколько ngChange
поддерживает только обновления взаимодействия с пользователем в соответствии с документацией
Так что теперь я смотрю на $scope.$watch
как Фредерик рекомендует:
$scope.$watch('MyProperty', function() {
$scope.log('changed from $watch');
});
Смотрите демо плункер
Но это кажется неправильным.
- Во-первых, это не декларативно, и вы должны искать код
MyTestProperty
найти эту привязку. - Если хотите, хотели бы разместить
$scope.log
в отдельной модели вы должны либо ввести$scope
или сделать привязку в контроллере. И, насколько я понимаю, оба способа не считаются лучшими практиками.
Некоторые люди думают, что $watch
это вообще плохо по ряду других причин. Но решение посоветовал там (который будет вызывать log
в ngClick напрямую) не имеет большого значения для меня. По сути, вы должны вручную отслеживать все изменения, и если приходит новый актер, вы должны скопировать туда свою логику.
Таким образом, вопросы будут: есть ли способ, который позволяет автоматически отслеживать обновления модели без $watch? И насколько плоха идея реализовать собственное средство для этого, если есть сейчас такой способ?
3 ответа
Есть несколько способов сделать это, но самый элегантный способ требует ngModel ввода, а затем использовать его для просмотра / манипулирования значением.
Вот ваш обновленный Plunker.
.directive('outputIt', function() {
return {
restrict: 'A',
scope: {
outputIt: '&'
},
require: '?ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
ngModelCtrl.$parsers.push(function(val) {
//console.log("the model was changed by input")
scope.outputIt()(val);
});
ngModelCtrl.$formatters.push(function(viewValue) {
//console.log("the model was changed from outside.");
scope.outputIt()(viewValue);
return viewValue;
});
}
}
})
Чтобы узнать больше об этом, вот очень классная статья об этом: Atricle
Удачи!
Вы смотрели в сторону ES5? По сути, это нативная функциональность $watch в javascript. Разница в том, что вы сохраняете функции set/get инкапсулированными со свойством, тогда как $watch может применяться снаружи где угодно.
var MyCtrl = function(){
this._selectedItem = null;
};
Object.defineProperty(MyCtrl.prototype, "selectedItem", {
get: function () {
return this._selectedItem;
},
set: function (newValue) {
this._selectedItem = newValue;
//Call method on update
this.onSelectedItemChange(this._selectedItem);
},
enumerable: true,
configurable: true
});
Конечно использовать:
<input type="number" />
Это создаст вам спиннер =)