J'ai une entrée de texte et je ne veux pas permettre aux utilisateurs d'utiliser des espaces, et tout ce qui est dactylographié sera transformé en minuscule.
Je sais que je ne suis pas autorisé à utiliser des filtres sur ng-model, par exemple.
ng-model='tags | lowercase | no_spaces'
J'ai envisagé de créer ma propre directive, mais l'ajout de fonctions à $parsers
et $formatters
n'a pas mis à jour l'entrée, mais uniquement aux autres éléments contenant ng-model
.
Comment puis-je modifier l'entrée de celle que je tape actuellement?
J'essaie essentiellement de créer la fonctionnalité 'tags' qui fonctionne exactement comme celle de StackOverflow.
Je suggérerais de regarder la valeur du modèle et de la mettre à jour au prochain changement: http://plnkr.co/edit/Mb0uRyIIv1eK8nTg3Qng?p=preview
Le seul problème intéressant concerne les espaces: Dans AngularJS 1.0.3, ng-model on input coupe automatiquement la chaîne. Par conséquent, il ne détecte pas que le modèle a été modifié si vous ajoutez des espaces à la fin ou au début (les espaces ne sont donc pas automatiquement supprimés par my. code). Mais dans 1.1.1 il y a une directive 'ng-trim' qui permet de désactiver cette fonctionnalité ( commit ). J'ai donc décidé d'utiliser la version 1.1.1 pour obtenir la fonctionnalité exacte que vous avez décrite dans votre question.
Je crois que l'intention des entrées AngularJS et de la directive ngModel
est que ne entrée non valide ne doit jamais se retrouver dans le modèle. Le modèle doit toujours être valide. Le problème avec un modèle non valide est que nous pouvons avoir des observateurs qui déclenchent et prennent des actions (inappropriées) basées sur un modèle non valide.
À mon avis, la solution appropriée consiste à se connecter au pipeline $parsers
et à s’assurer que les entrées non valides ne sont pas intégrées au modèle. Je ne suis pas sûr de savoir comment avez-vous essayé d'aborder les choses ou ce qui n'a pas fonctionné pour vous avec $parsers
mais voici une directive simple qui résout votre problème (ou du moins ma compréhension du problème):
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;
});
}
};
});
Dès que la directive ci-dessus est déclarée, elle peut être utilisée comme suit:
<input ng-model="sth" ng-trim="false" custom-validation>
Comme dans la solution proposée par @Valentyn Shybanov, nous devons utiliser la directive ng-trim
si nous voulons interdire les espaces au début/à la fin de l'entrée.
L'avantage de cette approche est double:
Une solution à ce problème pourrait être d’appliquer les filtres du côté du contrôleur:
$scope.tags = $filter('lowercase')($scope.tags);
N'oubliez pas de déclarer $filter
en tant que dépendance.
Si vous utilisez un champ de saisie en lecture seule, vous pouvez utiliser ng-value avec filter.
par exemple:
ng-value="price | number:8"
Utilisez une directive qui ajoute à la fois les collections $ formatters et $ parsers pour vous assurer que la transformation est effectuée dans les deux sens.
Voir cette autre réponse pour plus de détails, y compris un lien vers jsfiddle.
J'ai eu un problème similaire et utilisé
ng-change="handler(objectInScope)"
dans mon gestionnaire, j'appelle une méthode de objectInScope pour se modifier correctement (entrée grossière). Dans le contrôleur j'ai initié quelque part que
$scope.objectInScope = myObject;
Je sais que cela n’utilise pas de filtres sophistiqués ni d’observateurs ... mais c’est simple et fonctionne très bien. Le seul inconvénient, c’est que l’objetInScope est envoyé dans l’appel au gestionnaire ...
Si vous effectuez une validation complexe d’entrée asynchrone, il peut être intéressant d’abstraire ng-model
jusqu’à un niveau dans le cadre d’une classe personnalisée avec ses propres méthodes de validation.
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>
code
(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) })
};
})();
Tu peux essayer ça
$scope.$watch('tags ',function(){
$scope.tags = $filter('lowercase')($scope.tags);
});