I neeed an input field where I can enter only the values 1,2 or 3 so i\'m trying to build a directive which prevents all changes to the model if it doesn\'t match these valu
You could always listen to the keypress
event and prevent the character from making it through. Here is a plunker
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.validValues = ['a','1','2'];
});
app.directive('myValidator', function ($parse) {
return {
scope: {
validValues: '=validValues'
},
link: function (scope, elm, attrs) {
elm.bind('keypress', function(e){
var char = String.fromCharCode(e.which||e.charCode||e.keyCode), matches = [];
angular.forEach(scope.validValues, function(value, key){
if(char === value) matches.push(char);
}, matches);
if(matches.length == 0){
e.preventDefault();
return false;
}
});
}
}
});
I'd recommend using the ng-pattern-restrict
directive.
Get the library and simply decorate your input like so:
<input type="text" pattern="[0-9]+" ng-pattern-restrict />
GitHub: AlphaGit/ng-pattern-restrict
I've actually had to build onto and modify the answer form Ian Haggerty. His code worked well, until I started to test it in different ways. I was specifically trying to test for values less than 100, but I was getting some strange results.
If I had 100 in my input, then tried to insert a decimal to make it 10.0, Ian's fix didn't account for this and said it wasn't matching my regex (even though I allow up to two decimals). Turns out that it always appended the character that I pressed at the END of the string it was testing, even though I was inserting it in the middle.
My change was to store the original value on "keypress", then on "keyup" (or "change" if you prefer), it does the checking of the new value. If invalid, then it reverts back to the original.
Unfortunately it does update the model briefly, but at least it lets you type characters in the middle or beginning of the input value and still match against the regex correctly. In Angular 1.3, we can probably use ng-model-options="{debounce:250}" to counter this. Having any code that relies on this model change be indempotent helps immensely.
usage: <input ... validate-with="/^([\d]{1,2}\.[\d]{1,2}|\.?[\d]{1,2}|100)?$/" />
.directive("validateWith", [function(){
return {
restrict: "A",
link: function($scope, $el, $attrs){
var regexp = eval($attrs.validateWith);
var origVal;
// store the current value as it was before the change was made
$el.on("keypress", function(e){
origVal = $el.val();
});
// after the change is made, validate the new value
// if invalid, just change it back to the original
$el.on("keyup", function(e){
if(!regexp.test($el.val())){
$el.val(origVal);
}
});
}
}
}]);
I recently wrote a directive just for this. It takes a regExp object that validates the incoming key presses and only permits them if are valid:
// forces keystrokes that satisfy the regExp passed
app.directive("regExpRequire", function() {
var regexp;
return {
restrict: "A",
link: function(scope, elem, attrs) {
regexp = eval(attrs.regExpRequire);
var char;
elem.on("keypress", function(event) {
char = String.fromCharCode(event.which)
if(!regexp.test(elem.val() + char))
event.preventDefault();
})
}
}
})
Template usage: <input type="text" reg-exp-require="/^[a-zA-Z]$/">
Or in your case: <input type="text" reg-exp-require="/^[1-3]*$/">