Поддержка Getter & setter с ng-моделью в AngularJs
Я пытаюсь получить поддержку getter/setter для ng-модели, выполнив директиву, которая позаботится о получении и установке значений в/из представления/модели. Я почти там, но в конечном итоге получаю бесконечные $digest петли.
Идея состоит в том, чтобы установить ng-model = "$ someFieldToStoreInTheScope", а затем установить директиву getter/setter обновления между этим полем и функциями getter/setter.
Я использую $watch для обновления модели с использованием выражения setter, когда ngModelController обновляет поле в области, а другой смотрит, чтобы обновить это поле при изменении выражения getter.
Посмотрите: http://jsfiddle.net/BDyAs/10/
Html:
<div ng-app="myApp">
<body>
<form name="form">
<input type="text" ng-model="$ngModelValue" ng-model-getter-setter="get=getValue();set=setValue($value)"/> {{myDerivedValue}}
</form>
</body>
</div>
JS:
var myApp = angular.module('myApp', []);
myApp.directive(
{
'ngModelGetterSetter': function () {
return {
require: "ngModel",
controller: ctrl,
link: function(scope, element, attrs, ngModelCtrl)
{
var getterSetterExpression = attrs.ngModelGetterSetter;
var tokens = getterSetterExpression.split(";");
var getExpression = tokens[0].split("=")[1];
var setExpression = tokens[1].split("=")[1];
function updateViewValue()
{
var updateExpression = attrs.ngModel + "=" + getExpression;
scope.$eval(updateExpression);
}
function updateModelValue()
{
scope.$value = ngModelCtrl.$viewValue;
scope.$eval(setExpression);
}
updateViewValue();
scope.$watch(getExpression, updateViewValue);
scope.$watch(attrs.ngModel, updateModelValue);
}
};
}
});
function ctrl($scope) {
$scope.getValue = function ()
{
return $scope.myValue;
}
$scope.setValue = function (val)
{
$scope.myValue = val;
$scope.myDerivedValue = $scope.myValue * 2;
}
$scope.setValue(5);
setInterval(function () { $scope.setValue($scope.getValue() + 1); $scope.$apply(); }, 1000);
}
Я поместил setInterval() в свой код, чтобы изменить модель и посмотреть, правильно ли она распространяется в представлении.
Любая идея, почему существует бесконечный цикл дайджеста и как его удалить?
Ответы
Ответ 1
ПРИМЕЧАНИЕ AngularJs 1.3 теперь поддерживает Getter/Setter для ng-модели. Для получения дополнительной информации см. http://docs.angularjs.org/api/ng/directive/ngModelOptions.
Я мог бы разбить бесконечный цикл с дополнительными вызовами на
ngModelCtrl.$setViewValue()
и
ngModelCtrl.$render()
в обработчиках событий. Не уверен, что это лучший способ сделать это, хотя.
Смотрите скрипту: http://jsfiddle.net/BDyAs/12/
EDIT:
Я улучшил код еще больше в
http://jsfiddle.net/BDyAs/15/
разделив директиву в отдельных для геттера и сеттера.
Ответ 2
Я думаю, что на вопрос о нарушении цикла дайджеста был дан ответ. Вот другой, более чистый подход к той же проблеме, который не включает $watch
.
Если вам не нужно поддерживать устаревшие браузеры, используйте ECMAScript 5-аксессоры.
Просто добавьте свойство к вашему контроллеру angular:
Object.defineProperty(
$scope,
"accessorWrappedMyValue",
{
get : function() { return $scope.myValue; },
set : function(newValue) {
$scope.myValue = newValue;
$scope.myDerivedValue = $scope.myValue * 2;
},
configurable: true
});
Теперь все, что вам нужно сделать, это ссылка accessorWrappedMyValue
from ng-model
так:
<input type="text" ng-model="accessorWrappedMyValue" />
Дальнейшее чтение
Этот блог имеет приятное представление об аксессуарах ES5.
Используйте эту матрицу характеристик, чтобы решить, можете ли вы пойти с ES5 или нет. Интересными являются "Getter/Setter в инициализаторе свойств" и "Object.defineProperty".