2013-02-08 7 views
9

Testfall: http://jsbin.com/ahugeg/4/edit (Ein wenig lang)ändert Fokus auf Eingabe auf einem Schlüsselereignis in AngularJS

Im obigen Test Fall habe ich drei Eingangselemente, durch ng-repeat Richtlinie erzeugt. In diesem Testfall beabsichtige ich, dass das Drücken der Pfeile nach oben/unten in einem dieser Eingänge den Fokus auf den Eingang in die entsprechende Richtung richten sollte, wenn ein Eingang in dieser Richtung verfügbar ist.

Ich bin neu in AngularJS, also könnte ich auf eine einfache Art und Weise fehlen, dies zu tun. Wie auch immer, ich habe zwei neue Direktiven (on-up und on-down) definiert, um die Ereignisse nach oben und unten zu behandeln und die Methoden $scope.focusNext und $scope.focusPrev aufzurufen und den richtigen Eintrag zu übergeben, relativ zu dem sich der Fokus bewegen sollte. Hier stecke ich fest.

Ich weiß, es ist nicht die Winkel Weg mit DOM-Elemente in Controllern zu tun, aber ich kann nicht sehen, wie der Fokus kann als Attribut/Eigenschaft eines Modells zu sehen. Ich dachte sogar an eine separate $scope.focusedEntry, aber sollte ich dann Uhr für Änderungen auf dieser Eigenschaft? Auch wenn ich Änderungen erkenne, wie kann ich auf das Eingabeelement zugreifen, das dem zu fokussierenden Eintrag entspricht?

Jede Hilfe, wie dies getan werden sollte, wird sehr geschätzt.

Antwort

15

Ich schrieb diese und getestet es kurz - es tut, was Sie wollen, ohne all die zusätzliche Unordnung in Ihrem Controller und im HTML. Sehen Sie es funktioniert 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' ]; 
} 

Richtlinie:

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

Danke.Ihre Lösung hat mir die Idee und Motivation gegeben, alleine zu arbeiten. Ich habe einen etwas anderen Ansatz gewählt, indem ich eine Direktive für das Elternelement des 'ng-repeat'ed-Elements definiere, das den Selektor von 'input' annimmt, auf den der Fokus verschoben werden soll. Ich poste meine Lösung in einer Minute. Danke noch einmal. –

6

Ich hatte ein ähnliches Problem und verwendete diese einfache Anweisung. Es funktioniert als ng-Show und ng-hide Möchtegern nur mit dem Fokus, wenn es Attribut ist löst als wahr:

.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

Hah! Schöne und einfache Lösung. Vielen Dank. –

+0

Große Lösung. Sie müssen focusVal genauer prüfen. ng-show und ng-hide verwenden toBoolean (Wert), was leider eine private Winkelfunktion ist. Ich habe dies zu einem Service verschoben und boolean.toBoolean (focusVal) === true aufgerufen. – shapeshifter

4

Inspiriert von @ Trevor-Lösung, hier ist was ich ließ sich auf,

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

    }; 
}); 

Dies definiert ein Attribut focus-iter, das auf das Elternelement aller wiederholten Eingaben gesetzt werden soll. Sehen Sie dies in Aktion hier: http://jsbin.com/ahugeg/10/.

Der Vorteil gegenüber @ Trevor ist, dass ich einen beliebigen Selektor für den Wert focus-iter Attribut festlegen kann, um genau anzugeben, welche Elemente der Fokus springen sollte mit arbeiten. Als verrücktes Beispiel versuchen Sie focus-iter Attribut zu input:even :). Dies hilft, da in meiner Anwendung die input s mit ziemlich viel zusätzlichen Markup um sie kommen, im Gegensatz zum Testfall.

+0

Das ist eigentlich ziemlich nett, was du da gemacht hast. Ich mag, wie im Grunde alles funktioniert wie 'focus-iter =" form> * "'. –

+0

Danke. Oder sogar 'focus-iter =" [key-focus] "', wenn die Inputs 'key-focus' Attribute haben wie das Markup in Ihrer Antwort :) –

+0

kann mir bei der Eingabe in der Tabellenzelle helfen? –

Verwandte Themen