Как сделать двустороннюю фильтрацию в AngularJS?
Одна из интересных вещей, которую может сделать AngularJS, - это применить фильтр к определенному выражению привязки данных, что является удобным способом, например, применить специфическую для культуры валюту или форматирование даты свойств модели. Также хорошо иметь вычисленные свойства в области видимости. Проблема заключается в том, что ни одна из этих функций не работает с двусторонними сценариями привязки данных - только односторонняя привязка данных из области действия в представление. Кажется, это явное упущение в отличной библиотеке - или я что-то упустил?
В KnockoutJS я мог создать вычисляемое свойство для чтения / записи, которое позволило мне указать пару функций, одна из которых вызывается для получения значения свойства, а другая вызывается при установке свойства. Это позволило мне, например, реализовать ввод с учетом культуры - позволить пользователю вводить "$1,24" и анализировать его в плавающем элементе в 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/)
Элемент ввода становится очень запутанным, когда пользователь начинает печатать. Я улучшил его, разделив свойство на два свойства, одно для непарсированного значения и одно для анализируемого значения:
$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 ответ
Оказывается, есть очень элегантное решение, но оно не очень хорошо документировано.
Форматирование значений модели для отображения может быть обработано |
оператор и угловой formatter
, Оказывается, в ngModel есть не только список форматеров, но и список синтаксических анализаторов.
1. Используйте ng-model
создать двустороннюю привязку данных
<input type="text" ng-model="foo.bar"></input>
2. Создайте директиву в вашем угловом модуле, которая будет применяться к тому же элементу и которая зависит от 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 для контроллера модели также содержит краткое объяснение и обзор других доступных методов.