Mathew Berg
Mathew Berg

Reputation: 28750

Input autofocus attribute

I have places in my code where I have this:

<input data-ng-disabled="SOME_SCOPE_VARIABLE" />

I would like to be able to use it like this too:

<input data-ng-autofocus="SOME_SCOPE_VARIABLE" />

Or even better, mimicking how ng-style is done:

<input data-ng-attribute="{autofocus: SOME_SCOPE_VARIABLE}" />

Does this exist in the current version of AngularJS? I noticed in the code there's a BOOLEAN_ATTR which gets all the attr's that AngularJS supports. I don't want to modify that in fear of changing versions and forgetting to update.

Upvotes: 26

Views: 78648

Answers (10)

Raghav
Raghav

Reputation: 9628

Combining whar others mentioned above:

JS Code:

myApp.directive('ngAutofocus', ['$timeout', function ($timeout) {
    var linker = function ($scope, element, attrs) {
        $scope.$watch('pageLoaded', function (pageLoaded) {
            if (pageLoaded) {
                $timeout(function () {
                    element[0].focus();
                });
            }
        });
    };

    return {
        restrict: 'A',
        link: linker
    };
}]);

HTML:

  <input type="text" ng-model="myField" class="input-block-level edit-item" ng-autofocus>

Set pageLoaded to true from your initial load method of the page get:

    var loadData = function () {
        ..
        return $http.get(url).then(function (requestResponse) {
           $scope.pageLoaded = true;
......
}

Upvotes: 0

Shailesh Gehlot
Shailesh Gehlot

Reputation: 79

so without $timeout you can also use auto focus like this -

    <input type="text" ng-show="{{condition}}" class='input-class'></input>
    angular.element(document).ready(function(){
    angular.element('.input-class')[0].focus();
    });

Upvotes: 0

Chad von Nau
Chad von Nau

Reputation: 4404

You can do this with the built-in ngAttr attribute bindings.

<input ng-attr-autofocus="{{SOME_SCOPE_VARIABLE}}">

The autofocus attribute will be added if SOME_SCOPE_VARIABLE is defined (even if it's false), and will be removed if it's undefined. So I force falsy values to be undefined.

$scope.SOME_SCOPE_VARIABLE = someVar || undefined;

Upvotes: 15

byteC0de
byteC0de

Reputation: 5273

Create a directive like this

.directive('autoFocus', ['$timeout', function ($timeout) {
        return {
            restrict: 'A',
            link: function ($scope, $element) {
                $timeout(function () {
                    $element[0].focus();
                });
            }
        }



<input type="text" auto-focus class="form-control msd-elastic" placeholder="">

Upvotes: 1

Vijay Sani
Vijay Sani

Reputation: 1

<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>

<div ng-app="myApp" ng-controller="namesCtrl"> 
  <div ng-repeat="x in names">
     <input ng-attr-focus={{$first}} value="{{x.name + ', ' + x.country }}" />
  </div>
</div>

<script>

        var myApp = angular.module('myApp', []);
        myApp.controller('namesCtrl', function($scope) {
    $scope.names = [
        {name:'x1',country:'y1'},
        {name:'x2',country:'y2'},
        {name:'x3',country:'y3'}
    ];
});

        myApp.directive("focus", function(){
            return {
                restrict: "A",
                link: function link(scope, element, attrs) {

                      if(JSON.parse(attrs.focus)){
                          element[0].focus();
                      }
                }
            };
        });
</script>
</body>
</html>

had created above custom directive for one of my use case.

  • always focusses on first input element.
  • works for ajax data, browser back/forward buttons.
  • Tested on chrome and firefox(default autofocus is not supported here)

JSON.parse is used to parse string "true" returned from html to boolean true in JS.
another way to use attrs.focus === "true" for if condition.

Upvotes: 0

Nitya Kumar
Nitya Kumar

Reputation: 968

scope.doFocus = function () {
                $timeout(function () {
                        document.getElementById('you_input_id').focus();
                    });
            };

Upvotes: 1

Santiago Angel
Santiago Angel

Reputation: 1137

This directive should do the trick:

angular.module('utils.autofocus', [])
.directive('autofocus', ['$timeout', function($timeout) {
  return {
    restrict: 'A',
    scope: {'autofocus':'='}
    link : function($scope, $element) {
      $scope.$watch 'autofocus', function(focus){
        if(focus){
          $timeout(function() {
            $element[0].focus();
          });
        }
      }
    }
  }
}]);

Taken from here: https://gist.github.com/mlynch/dd407b93ed288d499778

Upvotes: 5

Thiago Negri
Thiago Negri

Reputation: 5351

I did it with two custom directives, something like this:

(function(angular) {
  'use strict';

  /* @ngInject */
  function myAutoFocus($timeout) {
    return {
      restrict: 'A',
      link: function(scope, element) {
        $timeout(function() {
          element[0].focus();
        }, 300);
      }
    };
  }

  function myFocusable() {
    return {
      restrict: 'A',
      link: function(scope, element, attrs) {
        var focusMethodName = attrs.myFocusable;
        scope[focusMethodName] = function() {
          element[0].focus();
        };
      }
    };
  }

  angular
    .module('myFocusUtils', [])
    .directive('myAutoFocus', myAutoFocus)
    .directive('myFocusable', myFocusable);

}(angular));

If you add attribute my-auto-focus to an element, it will receive focus after 300ms. I set the value to 300 instead of 0 to let other async components to load before setting the focus.

The attribute my-focusable will create a function in the current scope. This function will set focus to the element when called. As it creates something in the scope, be cautious to avoid overriding something.

This way you don't need to add something to Angular's digest cycle (watch) and can do it entirely in the view:

<input my-focusable="focusOnInput"></input>        
<button ng-click="focusOnInput()">Click to focus</button>

I created a JSFiddle to show the myFocusable directive: http://jsfiddle.net/8shLj3jc/

For some reason I don't know, the myAutoFocus directive does not work in JSFiddle, but it works in my page.

Upvotes: 0

Josh David Miller
Josh David Miller

Reputation: 120513

Update: AngularJS now has an ngFocus directive that evaluates an expression on focus, but I mention it here for the sake of completeness.


The current version of AngularJS doesn't have a focus directive, but it's in the roadmap. Coincidentally, we were talking about this on the mailing list yesterday, and I came up with this:

angular.module('ng').directive('ngFocus', function($timeout) {
    return {
        link: function ( scope, element, attrs ) {
            scope.$watch( attrs.ngFocus, function ( val ) {
                if ( angular.isDefined( val ) && val ) {
                    $timeout( function () { element[0].focus(); } );
                }
            }, true);

            element.bind('blur', function () {
                if ( angular.isDefined( attrs.ngFocusLost ) ) {
                    scope.$apply( attrs.ngFocusLost );

                }
            });
        }
    };
});

Which works off a scope variable as you requested:

<input type="text" ng-focus="isFocused" ng-focus-lost="loseFocus()">

Here's a fiddle: http://jsfiddle.net/ANfJZ/39/

Upvotes: 43

Dorian
Dorian

Reputation: 23999

What I did is using regular autofocus on my inputs: <input autofocus>

And then I set the focus on the first visible input with autofocus when angular is ready:

angular.element(document).ready(function() {
  $('input[autofocus]:visible:first').focus();
});

Hope this helps.

Upvotes: 0

Related Questions