Search code examples
validationangularjsangularjs-directivewcag

Set focus on first invalid input in AngularJs form


I've read several articles and StackOverflow questions relating to the setting of focus in AngularJs.

Unfortunately all the examples that I have read assume that there is some attribute that I can add to the element to gain focus, e.g. a focusMe directive.

However what if I don't know in advance which input to set focus to? In particular how do I set focus to the first input element in a form that has $invalid set - i.e. an element that fails validation. There could be several inputs that fail validation, so I cannot use a directive that just tries to call .focus() based on this. (I am doing this for Accessibility/WCAG reasons, its good practice to do so on submit being clicked to minimize keypresses to find the first field that has failed validation).

The $error object will give all controls that fail validation, but they are grouped by the type of failure not in any order of appearance on the form.

I'm sure I can come up with some kludged way of doing this. A directive on the form, which receives some broadcast when focus needs to be set - that directive can then search for the first $invalid element. However this seems very complex and I'd like to know whether these is a better more 'angular' way of doing this.


Solution

  • You can also use angular.element

    angular.element('input.ng-invalid').first().focus();
    

    View

    <form name="myForm" novalidate="novalidate" data-ng-submit="myAction(myForm.$valid)" autocomplete="off"></form>
    

    Controller

    $scope.myAction= function(isValid) {
        if (isValid) {
            //You can place your ajax call/http request here
        } else {
            angular.element('input.ng-invalid').first().focus();
        }
    };
    

    used ngMessages for validation

    The no jquery way

    angular.element($document[0].querySelector('input.ng-invalid')).focus();
    

    When using this method, need to pass $document as parameter in your angular controller

    angular.module('myModule')
    .controller('myController', ['$document', '$scope', function($document, $scope){
        // Code Here
    }]);