I have a text input and I don't want to allow users to use spaces, and everything typed will be turned into lowercase.
I know I'm not allowed to use filters on ng-model eg.
ng-model='tags | lowercase | no_spaces'
I looked at creating my own directive but adding functions to $parsers and $formatters didn't update the input, only other elements that had ng-model on it.
How can I change the input of that I'm currently typing in?
I'm essentially trying to create the 'tags' feature that works just like the one here on StackOverflow.
I believe that the intention of AngularJS inputs and the ngModel direcive is that invalid input should never ends up in the model. The model should be always valid. The problem with having invalid model is that we might have watchers that fire and take (inappropriate) actions based on invalid model.
In my eyes the proper solution here is to plug into the $parsers pipeline and make sure that invalid input doesn't make it into model. I'm not sure how did you try approach things or what exactly didn't work for you with $parsers but here is a simple directive that solves your problem (or at least my understanding of the problem):
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;
});
}
};
});
As soon as the above directive is declared it can be used like so:
<input ng-model="sth" ng-trim="false" custom-validation>
As in solution proposed by @Valentyn Shybanov we need to use the ng-trim directive if we want to disallow spaces at the beginning / end of the input.
The advantage of this approach is 2-fold:
I would suggest to watch model value and update it upon chage: http://plnkr.co/edit/Mb0uRyIIv1eK8nTg3Qng?p=preview
The only interesting issue is with spaces: In AngularJS 1.0.3 ng-model on input automatically trims string, so it does not detect that model was changed if you add spaces at the end or at start (so spaces are not automatically removed by my code). But in 1.1.1 there is 'ng-trim' directive that allows to disable this functionality (commit). So I've decided to use 1.1.1 to achieve exact functionality you described in your question.
A solution to this problem could be to apply the filters on controller side :
$scope.tags = $filter('lowercase')($scope.tags);
Don't forget to declare $filter as dependency.
I had a similar problem and used
ng-change="handler(objectInScope)"
in my handler I call a method of the objectInScope to modify itself correctly (coarse input). In the controller I have initiated somewhere that
$scope.objectInScope = myObject;
I know this doesn't use any fancy filters or watchers... but it's simple and works great. The only down-side to this is that the objectInScope is sent in the call to the handler...