Как сделать двустороннюю фильтрацию в AngularJS?
Одна из интересных вещей, которую может выполнять AngularJS, - это применить фильтр к определенному выражению привязки данных, что является удобным способом применения, например, для конкретной культуры или форматирования даты свойств модели. Также неплохо иметь вычисленные свойства в области. Проблема в том, что ни одна из этих функций не работает с сценариями двухсторонней привязки данных - только односторонняя привязка данных из области видимости. Это похоже на вопиющее упущение в отличной библиотеке - или я что-то не хватает?
В KnockoutJS я мог бы создать вычисляемое свойство чтения/записи, что позволило мне указать пару функций, которые вызывается, чтобы получить значение свойства, и тот, который вызывается, когда свойство задано. Это позволило мне реализовать, например, вход в систему, ориентированный на культуру, - позволяя пользователю вводить "$ 1.24" и анализируя это в float в ViewModel и иметь изменения в ViewModel, отраженные на входе.
Самое близкое, что я мог найти, похоже на использование $scope.$watch(propertyName, functionOrNGExpression);
. Это позволяет мне вызвать функцию, вызываемую при изменении свойства в $scope
. Но это не решает, например, проблему ввода в культуру. Обратите внимание на проблемы, когда я пытаюсь изменить свойство $watched
в самом методе $watch
:
$scope.$watch("property", function (newValue, oldValue) {
$scope.outputMessage = "oldValue: " + oldValue + " newValue: " + newValue;
$scope.property = Globalize.parseFloat(newValue);
});
(http://jsfiddle.net/gyZH8/2/)
Элемент ввода очень запутан, когда пользователь начинает печатать. Я улучшил его, разделив свойство на два свойства: одно для unparsed и одно для проанализированного значения:
$scope.visibleProperty= 0.0;
$scope.hiddenProperty = 0.0;
$scope.$watch("visibleProperty", function (newValue, oldValue) {
$scope.outputMessage = "oldValue: " + oldValue + " newValue: " + newValue;
$scope.hiddenProperty = Globalize.parseFloat(newValue);
});
(http://jsfiddle.net/XkPNv/1/)
Это было улучшение по сравнению с первой версией, но немного более подробное, и обратите внимание, что по-прежнему существует проблема свойства parsedValue
изменений области (введите что-то во втором входе, что изменяет parsedValue
непосредственно. заметьте, что верхний ввод не обновляется). Это может произойти из-за действия контроллера или загрузки данных из службы данных.
Есть ли более простой способ реализовать этот сценарий, используя AngularJS? Не хватает ли некоторых функций в документации?
Ответы
Ответ 1
Оказывается, там очень элегантное решение, но оно недостаточно хорошо документировано.
Форматирование значений модели для отображения может выполняться оператором |
и angular formatter
. Оказывается, что ngModel имеет не только список форматов, но и список парсеров.
1. Используйте ng-model
для создания двусторонней привязки данных
<input type="text" ng-model="foo.bar"></input>
2. Создайте директиву в своем модуле angular, который будет применен к тому же элементу, и который зависит от контроллера ngModel
module.directive('lowercase', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attr, ngModel) {
...
}
};
});
3. В рамках метода link
добавьте свои пользовательские преобразователи в контроллер ngModel
function fromUser(text) {
return (text || '').toUpperCase();
}
function toUser(text) {
return (text || '').toLowerCase();
}
ngModel.$parsers.push(fromUser);
ngModel.$formatters.push(toUser);
4. Добавьте новую директиву в тот же элемент, у которого уже есть ngModel
<input type="text" lowercase ng-model="foo.bar"></input>
Здесь рабочий пример, который преобразует текст в нижний регистр в input
и обратно в верхний регистр в модели
Документация API для Контроллера моделей также содержит краткое объяснение и обзор других доступных методов.