web-dev-qa-db-ja.com

要素フォーカスを斜めに設定

フォーカス要素を角度で設定する方法の例を調べた後、それらのほとんどがフォーカス設定を監視するためにいくつかの変数を使用し、フォーカスを設定したいフィールドごとに1つの異なる変数を使用します。多くのフィールドを持つフォームでは、それは多くの異なる変数を意味します。

Jqueryの方法を念頭に置いて、しかし角度のある方法でそれをしたいのですが、私は要素のidを使用して任意の関数にフォーカスを設定するという解決策を作りました。その方法は正しいです、何でも、私がこれをより良い角度で行うのを助けることができるものは何でも、持っています。

基本的には、ユーザーがdirectiveで定義したスコープ値、またはデフォルトのfocusElementを監視するディレクティブを作成し、その値が要素のidと同じ場合は、その要素セット自体がフォーカスを設定します。

angular.module('appnamehere')
  .directive('myFocus', function () {
    return {
      restrict: 'A',
      link: function postLink(scope, element, attrs) {
        if (attrs.myFocus == "") {
          attrs.myFocus = "focusElement";
        }
        scope.$watch(attrs.myFocus, function(value) {
          if(value == attrs.id) {
            element[0].focus();
          }
        });
        element.on("blur", function() {
          scope[attrs.myFocus] = "";
          scope.$apply();
        })        
      }
    };
  });

何らかの理由で焦点を合わせる必要がある入力は、このようにします。

<input my-focus id="input1" type="text" />

ここにフォーカスを設定するための任意の要素:

<a href="" ng-click="clickButton()" >Set focus</a>

そして、フォーカスを設定した関数例:

$scope.clickButton = function() {
    $scope.focusElement = "input1";
}

それは角度の良い解決策ですか?それは私の貧しい経験と私はまだ見ていないという問題がありますか?

108

あなたの解決策の問題点は、新しいスコープを作成する他のディレクティブに結び付けられているときうまくいかないことです。 ng-repeat。より良い解決策は、単純にあなたがあなたのコントローラ内で要素を命令的に集中させるか、またはHTMLで宣言的に要素を集中させることを可能にするサービス関数を作成することでしょう。

デモ

JAVASCRIPT

サービス

 .factory('focus', function($timeout, $window) {
    return function(id) {
      // timeout makes sure that it is invoked after any other event has been triggered.
      // e.g. click events that need to run before the focus or
      // inputs elements that are in a disabled state but are enabled when those events
      // are triggered.
      $timeout(function() {
        var element = $window.document.getElementById(id);
        if(element)
          element.focus();
      });
    };
  });

指令

  .directive('eventFocus', function(focus) {
    return function(scope, elem, attr) {
      elem.on(attr.eventFocus, function() {
        focus(attr.eventFocusId);
      });

      // Removes bound events in the element itself
      // when the scope is destroyed
      scope.$on('$destroy', function() {
        elem.off(attr.eventFocus);
      });
    };
  });

コントローラー

.controller('Ctrl', function($scope, focus) {
    $scope.doSomething = function() {
      // do something awesome
      focus('email');
    };
  });

HTML

<input type="email" id="email" class="form-control">
<button event-focus="click" event-focus-id="email">Declarative Focus</button>
<button ng-click="doSomething()">Imperative Focus</button>
172
ryeballar

この解決策については、ディレクティブを作成し、それを特定の条件が満たされたときにフォーカスを取得する必要があるDOM要素に添付するだけです。このアプローチに従うことによって、コントローラをDOM要素IDに結合することを避けます。

サンプルコードディレクティブ

gbndirectives.directive('focusOnCondition', ['$timeout',
    function ($timeout) {
        var checkDirectivePrerequisites = function (attrs) {
          if (!attrs.focusOnCondition && attrs.focusOnCondition != "") {
                throw "FocusOnCondition missing attribute to evaluate";
          }
        }

        return {            
            restrict: "A",
            link: function (scope, element, attrs, ctrls) {
                checkDirectivePrerequisites(attrs);

                scope.$watch(attrs.focusOnCondition, function (currentValue, lastValue) {
                    if(currentValue == true) {
                        $timeout(function () {                                                
                            element.focus();
                        });
                    }
                });
            }
        };
    }
]);

可能な使い方

.controller('Ctrl', function($scope) {
   $scope.myCondition = false;
   // you can just add this to a radiobutton click value
   // or just watch for a value to change...
   $scope.doSomething = function(newMyConditionValue) {
       // do something awesome
       $scope.myCondition = newMyConditionValue;
  };

;));

HTML

<input focus-on-condition="myCondition">
18
Braulio

DOMの検索、監視、そしてグローバルなエミッターは可能な限り避けるようにしたいので、もっと直接的なアプローチを使います。 directive要素に焦点を当てた単純な機能を割り当てるには、directiveを使用します。その後、コントローラの範囲内で必要なときにその関数を呼び出します。

これをスコープに適用するための簡単な方法を紹介します。 controller-as構文を扱うための完全なスニペットを見てください。

指令:

app.directive('inputFocusFunction', function () {
    'use strict';
    return {
        restrict: 'A',
        link: function (scope, element, attr) {
            scope[attr.inputFocusFunction] = function () {
                element[0].focus();
            };
        }
    };
});

そしてhtmlで:

<input input-focus-function="focusOnSaveInput" ng-model="saveName">
<button ng-click="focusOnSaveInput()">Focus</button>

またはコントローラで:

$scope.focusOnSaveInput();
angular.module('app', [])
  .directive('inputFocusFunction', function() {
    'use strict';
    return {
      restrict: 'A',
      link: function(scope, element, attr) {
        // Parse the attribute to accomodate assignment to an object
        var parseObj = attr.inputFocusFunction.split('.');
        var attachTo = scope;
        for (var i = 0; i < parseObj.length - 1; i++) {
          attachTo = attachTo[parseObj[i]];
        }
        // assign it to a function that focuses on the decorated element
        attachTo[parseObj[parseObj.length - 1]] = function() {
          element[0].focus();
        };
      }
    };
  })
  .controller('main', function() {});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>

<body ng-app="app" ng-controller="main as vm">
  <input input-focus-function="vm.focusOnSaveInput" ng-model="saveName">
  <button ng-click="vm.focusOnSaveInput()">Focus</button>
</body>

を編集して、このアプローチの理由についてより多くの説明を提供し、コントローラとして使用するためのコードスニペットを拡張しました。

11
cstricklan

あなたが試すことができます

angular.element('#<elementId>').focus();

例えば。

angular.element('#txtUserId').focus();

それは私のために働いています。

9
Anoop

もう1つの選択肢は、ディレクティブにフォーカスするよう通知するためにAngularの組み込みpub-subアーキテクチャを使用することです。他のアプローチと似ていますが、プロパティに直接結び付けられているわけではなく、代わりに特定のキーのスコープをリッスンしています。

指令:

angular.module("app").directive("focusOn", function($timeout) {
  return {
    restrict: "A",
    link: function(scope, element, attrs) {
      scope.$on(attrs.focusOn, function(e) {
        $timeout((function() {
          element[0].focus();
        }), 10);
      });
    }
  };
});

HTML:

<input type="text" name="text_input" ng-model="ctrl.model" focus-on="focusTextInput" />

コントローラ:

//Assume this is within your controller
//And you've hit the point where you want to focus the input:
$scope.$broadcast("focusTextInput");
4
Mattygabe

私は表現を使うほうが好きでした。これにより、フィールドが有効で、一定の長さに達したとき、そしてもちろんロード後に、ボタンにフォーカスを合わせるなどのことができます。

<button type="button" moo-focus-expression="form.phone.$valid">
<button type="submit" moo-focus-expression="smsconfirm.length == 6">
<input type="text" moo-focus-expression="true">

複雑な形式では、これは焦点を合わせるために追加のスコープ変数を作成する必要性も減らします。

https://stackoverflow.com/a/29963695/937997 を参照してください。

3
winry