When enforcing input values to conform to certain rules using an ngModelController $parser function, the $parser function isn't called on repeated "invalid" keystrokes, which allows invalid characters to get added.
In the example below, the directive is meant to remove all non-digit characters. it mostly works, but if you type the same non-digit character twice in a row (e.g. 'xx'), a single 'x' will show up in the input. if you type 'x' a third time, it will remove the 'x'.
I've also included a failing test case.
all code is running at http://codepen.io/visnup/pen/YXgLVq?editors=101
directive usage
<div ng-app="digits">
<input ng-model="number" placeholder="digits only" digits-only />
</div>
directive
angular
.module('digits', [])
.directive('digitsOnly', function() {
return {
require: 'ngModel',
link: function link(scope, element, attrs, ngModel) {
ngModel.$parsers.push(function(value) {
var numbers = value.replace(/\D/g, '');
element.val(numbers);
return numbers;
});
}
};
});
failing test case
describe('digits', function() {
beforeEach(angular.mock.module('digits'));
let scope, input;
beforeEach(inject(function($compile, $rootScope) {
scope = $rootScope;
input = $compile('<input ng-model="number" digits-only />')(scope);
}));
// works
it('should block non-digits', function() {
input.val('111x');
input.triggerHandler('input');
expect(input.val()).to.equal('111');
});
// doesn't work
it('should not flash incorrect input', function() {
input.val('111x');
input.triggerHandler('input');
input.val('111x');
input.triggerHandler('input');
expect(input.val()).to.equal('111');
});
});
This has been brought up before in #10700.