Как сделать двустороннюю фильтрацию в 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 для контроллера модели также содержит краткое объяснение и обзор других доступных методов.

Другие вопросы по тегам