CMLee CMLee - 6 months ago 22
AngularJS Question

How can I reset an input field using Angularjs when the backspace/delete keys are pressed?

How can I reset an input field using Angularjs when the backspace/delete keys are pressed?

I have used this awesome directive and it has worked well, except when the user clears the field with backspace or delete key. Then the validations prevent the user from submitting the form (using Chrome v.50.0.2661.102).

I've tried modifying the directive, but without success. Any help is much appreciated.

Here's the directive with my modifications in the el.bind():

angular.module(myApp)
.directive('resetField',
function resetField($compile, $timeout) {
return {
require: 'ngModel',
scope: {},
transclusion: true,
link: function (scope, el, attrs, ctrl) {
// limit to input element of specific types
var inputTypes = /text|search|tel|url|email|password/i;
if (el[0].nodeName !== "INPUT")
throw new Error("resetField is limited to input elements");
if (!inputTypes.test(attrs.type))
throw new Error("Invalid input type for resetField: " + attrs.type);

// compiled reset icon template
var template = $compile('<i ng-show="enabled" ng-mousedown="reset()" class="fa fa-times-circle"></i>')(scope);
el.addClass('reset-field');
el.after(template);

scope.reset = function () {
ctrl.$setViewValue(null);
ctrl.$render();
$timeout(function () {
el[0].focus();
}, 0, false);
scope.enabled = false;
};

el.bind('input', function () {

//I added this snippet since the directive on its own works so
// well, (thought scope.reset() above would do the trick) but it
//doesn't pass the validations... thus the remaining code
if (ctrl.$isEmpty(el.val())) {
scope.reset();

el[0].classList.remove('ng-dirty');
el[0].classList.remove('ng-touched');
el[0].classList.add('ng-pristine');
el[0].classList.remove('ng-invalid-required');
el[0].classList.add('ng-pristine');
el[0].classList.add('ng-valid');

} else {
scope.enabled = !ctrl.$isEmpty(el.val());
}
scope.$apply();
})
.bind('focus', function () {
$timeout(function () {
scope.enabled = !ctrl.$isEmpty(el.val());
scope.$apply();
}, 0, false);
})
.bind('blur', function () {
$timeout(function () {
scope.enabled = false;
}, 0, false);

});
}
};
};
);


The html still shows ng-invalid-required because a depending field that has been reset with backspace is not null.

If I'm calling the exact same call as clicking on the "X", why doesn't it function the same way?

Answer

The validity settings are stored on the input directive's controller, so removing the class names in the HTML doesn't matter - they'll just get re-added during the next digest.

However, you have access to the ngModel controller in your directive - passed into the link() function as ctrl - so you can call the methods there to manually "set" its validity/pristine-ness.

Here's a quick demo (the original directive author's example, plus your above code, modified): http://jsbin.com/wuwezelige/1/edit?html,js,output

I've made the first field required, and it also has an ng-pattern regex that it must match to be valid. When you backspace, the fields classes reset to mark it as pristine and valid

Hope this helps.

Reference:
https://docs.angularjs.org/api/ng/type/ngModel.NgModelController https://docs.angularjs.org/api/ng/type/form.FormController

Comments