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.
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.
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.
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.
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();
}
}
});
}
};
});
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);
}
});
}
}
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With