Reputation: 2092
I have this directive that runs in <input type='text'>
to restrict the user input to type only numbers. Works fine!
My problem is that if the user copy/paste some string, angular is accepting the value and sending the string to the backend.
angular.module('autonumeric', []).directive('ngNumeric', [function () {
'use strict';
// Declare a empty options object
var options = {};
return {
// Require ng-model in the element attribute for watching changes.
require: '?ngModel',
// This directive only works when used in element's attribute (e.g: cr-numeric)
restrict: 'A',
compile: function (tElm, tAttrs) {
var isTextInput = tElm.is('input:text');
return function (scope, elm, attrs, controller) {
// Get instance-specific options.
var opts = angular.extend({}, options, scope.$eval(attrs.crNumeric));
// Helper method to update autoNumeric with new value.
var updateElement = function (element, newVal) {
// Only set value if value is numeric
if ($.isNumeric(newVal))
element.autoNumeric('set', newVal);
};
// Initialize element as autoNumeric with options.
elm.autoNumeric(opts);
// if element has controller, wire it (only for <input type="text" />)
if (controller && isTextInput) {
// render element as autoNumeric
controller.$render = function () {
updateElement(elm, controller.$viewValue);
}
// watch for external changes to model and re-render element
scope.$watch(tAttrs.ngModel, function (current, old) {
//controller.$render();
updateElement(elm, controller.$viewValue);
});
// Detect changes on element and update model.
elm.on('change', function (e) {
scope.$apply(function () {
controller.$setViewValue(elm.autoNumeric('get'));
});
});
}
else {
// Listen for changes to value changes and re-render element.
// Useful when binding to a readonly input field.
if (isTextInput) {
attrs.$observe('value', function (val) {
updateElement(elm, val);
});
}
}
}
} // compile
} // return
}]);
I tried to use replace with a regex replace(/[^0-9.]/g, '')
to remove all characters, but is not working.
Does someone have some idea how to improve this directive to accept only numbers even on copying/pasting?
Upvotes: 2
Views: 3439
Reputation: 113
Generally I think you're much better off by using <input type='number'>
. Also remember that your backend should be robust and you shouldn't trust what comes from the client, even with your fancy directive.
If you however insist on using a text input maybe you can get some inspiration from this directive.
app.directive('ngNumeric', [function () {
return {
restrict: 'E',
require: 'ngModel',
scope: {
model: '=ngModel'
},
compile: compile,
replace: true,
template: '<input type="text" ng-change="change()">'
}
function compile() {
return link
}
function link(scope, element) {
scope.change = function() {
var numeric = element.val().replace(/[^0-9]/g, '')
console.log('I changed', element.val())
element.val(numeric)
scope.model = numeric
}
}
}]);
Upvotes: 0
Reputation: 18279
I've written a similar directive that only allows floats (and also convert ,
to .
). It is simplest that your, so I think you could use it:
angular.module('myMod').directive('floatOnly', function() {
return {
require: 'ngModel',
restrict: 'A',
link: function(scope, element, attrs, modelCtrl) {
modelCtrl.$parsers.push(function(inputValue) {
if(inputValue === undefined) return '';
// Remove forbidden characters
cleanInputValue = inputValue.replace(',', '.') // change commas to dots
.replace(/[^\d.]/g, '') // keep numbers and dots
.replace(/\./, "x") // change the first dot in X
.replace(/\./g, "") // remove all dots
.replace(/x/, "."); // change X to dot
if(cleanInputValue != inputValue) {
modelCtrl.$setViewValue(cleanInputValue);
modelCtrl.$render();
}
return cleanInputValue;
});
}
}
});
You can use it as follow:
<input type="text" ng-model="myFloat" float-only/>
Upvotes: 1