Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change focus to input on a key event in AngularJS

Tags:

angularjs

Test case: http://jsbin.com/ahugeg/4/edit (Slightly long)

In the above test case, I have three input elements, generated by ng-repeat directive. My intention in this test case, is that hitting the up/down arrows in one of these inputs should move focus to the input in the corresponding direction, if there is an input available in that direction.

I am new to AngularJS, so I might be missing on some straightforward way to do this. Anyway, I defined two new directives (on-up and on-down), to handle the up and down events and am calling the $scope.focusNext and $scope.focusPrev methods, passing the correct entry, relative to which the focus should move. This is where I am stuck.

I know it is not the angular-way to deal with DOM elements in controllers, but I can't see how the focus can be seen as an attribute/property of a model. I even thought of having a separate $scope.focusedEntry, but then should I watch for changes on that property? Even if I do and I detect changes, how can I access the input element corresponding to the entry I want focused?

Any help on how this should be done are very much appreciated.

like image 263
sharat87 Avatar asked Feb 08 '13 17:02

sharat87


People also ask

How to focus on element in AngularJS?

The ng-focus directive tells AngularJS what to do when an HTML element gets focus. The ng-focus directive from AngularJS will not override the element's original onfocus event, both will be executed.

What is Ng Keydown?

The ng-keydown directive tells AngularJS what to do when the keyboard is used on the specific HTML element. The ng-keydown directive from AngularJS will not override the element's original onkeydown event, both will be executed.

What is angular autofocus?

HTML form elements already provide for an “autofocus” attribute that will pull focus to an input field after it is rendered on the page. HTML5 autofocus. The problem is when you move the one to another pages using the angular router on single page application.


2 Answers

I just wrote this up and tested it briefly - it does what you want without all the extra clutter in your controller and in the HTML. See it working here.

HTML:

<body ng-controller="Ctrl">
    <input ng-repeat="entry in entries" value="{{entry}}" key-focus />
</body>

Controller:

function Ctrl($scope) {
  $scope.entries = [ 'apple', 'ball', 'cow' ];
}

Directive:

app.directive('keyFocus', function() {
  return {
    restrict: 'A',
    link: function(scope, elem, attrs) {
      elem.bind('keyup', function (e) {
        // up arrow
        if (e.keyCode == 38) {
          if(!scope.$first) {
            elem[0].previousElementSibling.focus();
          }
        }
        // down arrow
        else if (e.keyCode == 40) {
          if(!scope.$last) {
            elem[0].nextElementSibling.focus();
          }
        }
      });
    }
  };
});
like image 107
Jay Avatar answered Sep 30 '22 06:09

Jay


I had a similar problem and used this simple directive. It works as ng-show and ng-hide would- only with focus, if it's attribute resolves as true:

.directive('focusOn',function() {
    return {
        restrict : 'A', 
        link : function($scope,$element,$attr) {
            $scope.$watch($attr.focusOn,function(focusVal) {
                if(focusVal === true) {
                    setTimeout(function() {
                        $element.focus();
                    },50);
                }
            });
        }
    }
})
like image 30
koolunix Avatar answered Sep 30 '22 06:09

koolunix