фильтры на ng-модели во входе
у меня есть текстовый ввод, и я не хочу, чтобы пользователи использовали пробелы, и все набранное будет превращено в нижний регистр.
Я знаю, что мне не разрешено использовать фильтры на ng-модели, например.
ng-model='tags | lowercase | no_spaces'
Я посмотрел на создание моей собственной директивы, но добавление функций в $parsers
и $formatters
не обновлял вход, только другие элементы, которые имели ng-model
на нем.
как я могу изменить ввод, который я сейчас набираю?
Я по существу пытаюсь создать функцию 'теги', которая работает так же, как здесь, на StackOverflow.
8 ответов:
Я бы предложил посмотреть значение модели и обновить его на chage:http://plnkr.co/edit/Mb0uRyIIv1eK8nTg3Qng?p=preview
единственная интересная проблема связана с пробелами: в AngularJS 1.0.3 ng-model на входе автоматически обрезается строка, поэтому она не обнаруживает, что модель была изменена, если вы добавляете пробелы в конце или в начале (поэтому пробелы автоматически не удаляются моим кодом). Но в 1.1.1 есть директива' ng-trim', которая позволяет отключить эту функцию (commit). Поэтому я решил использовать 1.1.1 для достижения точной функциональности, описанной в вашем вопросе.
Я считаю, что намерение AngularJS входов и
ngModel
direcive заключается в том, что недопустимый ввод никогда не должен заканчиваться в модели. Модель всегда должна быть действительной. Проблема с наличием недопустимой модели заключается в том, что у нас могут быть наблюдатели, которые запускают и принимают (неуместные) действия на основе недопустимой модели.как я вижу, правильным решением здесь является подключение к
$parsers
конвейер и убедитесь, что недопустимый ввод не попадает в модель. Я не уверен как вы пытались подойти к вещам или что именно не сработало для вас с$parsers
но вот простая директива, которая решает ваши проблемы (или, по крайней мере мое понимание проблемы):app.directive('customValidation', function(){ return { require: 'ngModel', link: function(scope, element, attrs, modelCtrl) { modelCtrl.$parsers.push(function (inputValue) { var transformedInput = inputValue.toLowerCase().replace(/ /g, ''); if (transformedInput!=inputValue) { modelCtrl.$setViewValue(transformedInput); modelCtrl.$render(); } return transformedInput; }); } }; });
как только вышеуказанная директива объявлена, ее можно использовать следующим образом:
<input ng-model="sth" ng-trim="false" custom-validation>
как в решение, предложенное @Шибанов Валентин нужно использовать
ng-trim
директива, если мы хотим запретить пробелы в начале / конце ввода.преимущество этот подход является 2-кратным:
- недопустимое значение не распространяется на модель
- С помощью директивы легко добавить эту пользовательскую проверку на любой вход без дублирования наблюдателей снова и снова
решением этой проблемы может быть применение фильтров на стороне контроллера:
$scope.tags = $filter('lowercase')($scope.tags);
Не забудьте объявить
$filter
как зависимость.
используйте директиву, которая добавляет к коллекциям $formatters и $parsers, чтобы гарантировать, что преобразование выполняется в обоих направлениях.
посмотреть это другой ответ для более подробной информации, включая ссылку на jsfiddle.
у меня была аналогичная проблема и использовал
ng-change="handler(objectInScope)"
в моем обработчике я вызываю метод objectInScope, чтобы изменить себя правильно (грубый ввод). В контроллере я инициировал где-то что
$scope.objectInScope = myObject;
Я знаю, что это не использует никаких причудливых фильтров или наблюдателей... но это просто и отлично работает. Единственным недостатком этого является то, что objectInScope отправляется в вызове обработчику...
Если вы используете поле ввода только для чтения, вы можете использовать ng-значение с фильтром.
например:
ng-value="price | number:8"
вы можете попробовать это
$scope.$watch('tags ',function(){ $scope.tags = $filter('lowercase')($scope.tags); });
Если вы делаете сложную, асинхронную проверку ввода, возможно, стоит абстрагироваться
ng-model
до одного уровня как часть пользовательского класса с собственными методами проверки.https://plnkr.co/edit/gUnUjs0qHQwkq2vPZlpO?p=preview
html
<div> <label for="a">input a</label> <input ng-class="{'is-valid': vm.store.a.isValid == true, 'is-invalid': vm.store.a.isValid == false}" ng-keyup="vm.store.a.validate(['isEmpty'])" ng-model="vm.store.a.model" placeholder="{{vm.store.a.isValid === false ? vm.store.a.warning : ''}}" id="a" /> <label for="b">input b</label> <input ng-class="{'is-valid': vm.store.b.isValid == true, 'is-invalid': vm.store.b.isValid == false}" ng-keyup="vm.store.b.validate(['isEmpty'])" ng-model="vm.store.b.model" placeholder="{{vm.store.b.isValid === false ? vm.store.b.warning : ''}}" id="b" /> </div>
код
(function() { const _ = window._; angular .module('app', []) .directive('componentLayout', layout) .controller('Layout', ['Validator', Layout]) .factory('Validator', function() { return Validator; }); /** Layout controller */ function Layout(Validator) { this.store = { a: new Validator({title: 'input a'}), b: new Validator({title: 'input b'}) }; } /** layout directive */ function layout() { return { restrict: 'EA', templateUrl: 'layout.html', controller: 'Layout', controllerAs: 'vm', bindToController: true }; } /** Validator factory */ function Validator(config) { this.model = null; this.isValid = null; this.title = config.title; } Validator.prototype.isEmpty = function(checkName) { return new Promise((resolve, reject) => { if (/^\s+$/.test(this.model) || this.model.length === 0) { this.isValid = false; this.warning = `${this.title} cannot be empty`; reject(_.merge(this, {test: checkName})); } else { this.isValid = true; resolve(_.merge(this, {test: checkName})); } }); }; /** * @memberof Validator * @param {array} checks - array of strings, must match defined Validator class methods */ Validator.prototype.validate = function(checks) { Promise .all(checks.map(check => this[check](check))) .then(res => { console.log('pass', res) }) .catch(e => { console.log('fail', e) }) }; })();