Change focus to input on a key event in AngularJS

后端 未结 3 1575
有刺的猬
有刺的猬 2021-02-03 11:49

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 intentio

相关标签:
3条回答
  • 2021-02-03 12:25

    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();
              }
            }
          });
        }
      };
    });
    
    0 讨论(0)
  • 2021-02-03 12:26

    Inspired by @Trevor's solution, here's what I settled on,

    app.directive('focusIter', function () {
    
        return function (scope, elem, attrs) {
            var atomSelector = attrs.focusIter;
    
            elem.on('keyup', atomSelector, function (e) {
                var atoms = elem.find(atomSelector),
                    toAtom = null;
    
                for (var i = atoms.length - 1; i >= 0; i--) {
                    if (atoms[i] === e.target) {
                        if (e.keyCode === 38) {
                            toAtom = atoms[i - 1];
                        } else if (e.keyCode === 40) {
                            toAtom = atoms[i + 1];
                        }
                        break;
                    }
                }
    
                if (toAtom) toAtom.focus();
    
            });
    
            elem.on('keydown', atomSelector, function (e) {
                if (e.keyCode === 38 || e.keyCode === 40)
                    e.preventDefault();
            });
    
        };
    });
    

    This defines an attribute focus-iter to be set on the parent element of all the repeated inputs. See this in action here: http://jsbin.com/ahugeg/10/.

    The advantage over @Trevor's is that I can set an arbitrary selector for the value of focus-iter attribute to specify exactly which elements the focus jumping should work with. As a crazy example, try setting focus-iter attribute to input:even :). This helps since in my application, the inputs come with quite a bit of extra markup around them, unlike the test case.

    0 讨论(0)
  • 2021-02-03 12:43

    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);
                    }
                });
            }
        }
    })
    
    0 讨论(0)
提交回复
热议问题