Reputation: 163
I have an iOS app using angularJS and ionic. I am trying to get the keyboard focus on to the next input field when the 'Return' button is hit. Here is the HTML code where the ng-repeat exists:
<div class="row item-list" ng-repeat="item in shoppingList">
<div class="col col-10 col-check" ng-click="checkItem($index)">
<i class="icon ion-checkmark-round" ng-if="item.Action == 'check'"></i>
</div>
<div class="col col-memo" ng-click="updateMemo($index)">
<label class="item-list item-input">
<input id="inputText" type="text" placeholder="" ng-model="item.EventContent" on-return="nextLine($index)"/>
</label>
</div>
</div>
You can see in my input element I have "on-return="nextLine($index)"". There I am using my custom directive which is used when the return button is hit:
.directive('onReturn', function () {
return function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
if (event.which === 13) {
scope.$apply(function () {
scope.$eval(attrs.onReturn);
});
event.preventDefault();
}
});
};
});
Which calls my nextLine function in my controller:
myScope.nextLine = function (index) {
//get next html input element and .setFocus()
}
Where index is the current input box index. I need a way to get the next HTML input element and set the focus there. Any help is appreciated.
Upvotes: 1
Views: 1377
Reputation: 2932
First of all, it's not recommended to use multiple instances of directives with DOM event listeners. What if you had 1000 directives listening to the same "keydown" event? That would totally choke the system.
Perhaps you should approach this with good old jQuery: add a "keydown" event listener to a container element, and then iterate over the input fields on each "return" keypress: Working demo here
A simplified version of the template :
<div class="items-lists" on-return>
<input type="text" ng-repeat="item in shoppingList" class="item-list">
</div>
And then in your Directive :
angular.module('MyApp')
.directive('onReturn', function() {
return {
restrict: 'A',
link: function(scope, element, attr) {
$(element).on("keydown keypress", function(event) {
if (event.which === 13) {
scope.nextLine();
event.preventDefault();
}
});
//get next html input element and set focus()
scope.nextLine = function() {
var nextInput = $(element).find('input:focus').next('input');
var firstInput = $(element).find('input')[0];
nextInput.length ? nextInput.focus() : firstInput.focus();
}
}
}
});
Solution #2:
Another approach would be to use an ng-focus
directive and bind it to a boolean expression. In this example, clicking an item will programmatically set it as focused by changing item.selected
to true
and deselect other items:
<div class="items-lists">
<input ng-repeat="item in shoppingList" ng-focus="item.selected" ng-click="selectItem(item)" class="item-list">
</div>
Upvotes: 1
Reputation: 1597
In my experience, a more event driven method is better suited to focus management. Pass the event to your nextLine method. Assuming you are only using jQuery light you would end up with something like this:
//add closest method to jQuery light
$.fn.closest = function (selector) {
var el = this[0];
while (el && self.matches(el, selector)) {
el = el.parentElement;
}
return $(el);
};
myScope.nextLine = function (event) {
var nextInput = $(event.target).closest("[ng-repeat]").find("input");
if(nextInput[0]){
nextInput[0].focus();
}
}
Upvotes: 1