1
votes

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.

2
Don't use scope.$apply directly, instead wrap in $timeout() - it does a "smart" use of $apply - not a "brutal" one.DotBot

2 Answers

1
votes

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();
  }
}
1
votes

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'd be nuts.

Perhaps you should approach this with good 'ol Jquery: add a "keydown" event listener to a container element, and then simply iterate over the input-fields with each "return" pressed. : 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 using ng-focus that accepts a Boolean expression. You could create an ng-click function for every item inside your ng-repeat, that sets it as "selected" and deselect the rest. Then evaluate item.selected in your input fields to achieve focus:

<div class="items-lists">
    <input ng-repeat="item in shoppingList" ng-focus="item.selected" ng-click="selectItem(item)" class="item-list">
</div>