In your directive you only specify a $parser.
A $parser takes effect when the $viewValue is changed, i.e. through interaction with the view (or programmatically setting the $viewValue).
But you are not touching the $viewValue, only the $modelValue.
If you want to perform validation when the $modelValue changes, you need to specify a $formatter as well.
E.g. add the following code in your linking function:
ctrl.$formatters.push(function (modelValue) {
if (modelValue && !INTEGER_REGEXP.test(modelValue)) {
ctrl.$setValidity('integer', false);
} else {
ctrl.$setValidity('integer', true);
}
// Return the original value regardless of its validity,
// so it shows up in the view (even if it is invalid).
return modelValue;
});
See, also, this short demo.
UPDATED:
I updated the code above and the demo to take into account the case of empty values and also properly re-validate when the $modelValue is changed programmatically.