入力フィールドにフォーカスを設定するにはどうすればよいですか?


759

AngularJSの入力フィールドにフォーカスを設定する「Angularの方法」とは何ですか?

より具体的な要件:

  1. モーダルを開いたら、<input>このモーダル内の事前定義されたものにフォーカスを設定します。
  2. <input>ボタンがクリックされるなどして表示されるたびに、フォーカスを合わせます。

私は、最初の要件を達成しようとしたとしautofocusますが、これはモーダルが初めて開かれ、唯一の特定のブラウザで(Firefoxでそれが動作しないなど)ときにのみ機能します。

どんな助けでもありがたいです。

回答:


579
  1. モーダルを開いたら、このモーダル内の事前定義された<input>にフォーカスを設定します。

ディレクティブを定義し、プロパティ/トリガーを$ watchして、要素にいつフォーカスするかがわかるようにします。

Name: <input type="text" focus-me="shouldBeOpen">

app.directive('focusMe', ['$timeout', '$parse', function ($timeout, $parse) {
    return {
        //scope: true,   // optionally create a child scope
        link: function (scope, element, attrs) {
            var model = $parse(attrs.focusMe);
            scope.$watch(model, function (value) {
                console.log('value=', value);
                if (value === true) {
                    $timeout(function () {
                        element[0].focus();
                    });
                }
            });
            // to address @blesh's comment, set attribute value to 'false'
            // on blur event:
            element.bind('blur', function () {
                console.log('blur');
                scope.$apply(model.assign(scope, false));
            });
        }
    };
}]);

プランカー

$ timeoutは、モーダルにレンダリングする時間を与えるために必要なようです。

「2」<input>が表示されるたびに(ボタンをクリックするなどして)、それにフォーカスを設定します。

基本的に上記のようなディレクティブを作成します。いくつかのスコーププロパティを監視し、それがtrueになったら(ng-clickハンドラーで設定)、を実行しelement[0].focus()ます。ユースケースに応じて、これに$ timeoutが必要な場合と不要な場合があります。

<button class="btn" ng-click="showForm=true; focusInput=true">show form and
 focus input</button>
<div ng-show="showForm">
  <input type="text" ng-model="myInput" focus-me="focusInput"> {{ myInput }}
  <button class="btn" ng-click="showForm=false">hide form</button>
</div>

app.directive('focusMe', function($timeout) {
  return {
    link: function(scope, element, attrs) {
      scope.$watch(attrs.focusMe, function(value) {
        if(value === true) { 
          console.log('value=',value);
          //$timeout(function() {
            element[0].focus();
            scope[attrs.focusMe] = false;
          //});
        }
      });
    }
  };
});

プランカー


2013年7月更新:元の分離スコープディレクティブを使用していて、埋め込み入力フィールド(つまり、モーダルの入力フィールド)で問題が発生する人が何人かいるのを目にしました。新しいスコープ(または、場合によっては新しい子スコープ)を持たないディレクティブは、いくつかの問題を軽減するはずです。したがって、上記で分離スコープを使用しないように回答を更新しました。以下は元の答えです:

1.の元の回答、分離スコープを使用:

Name: <input type="text" focus-me="{{shouldBeOpen}}">

app.directive('focusMe', function($timeout) {
  return {
    scope: { trigger: '@focusMe' },
    link: function(scope, element) {
      scope.$watch('trigger', function(value) {
        if(value === "true") { 
          $timeout(function() {
            element[0].focus(); 
          });
        }
      });
    }
  };
});

プランカー

2.の元の回答、分離スコープを使用:

<button class="btn" ng-click="showForm=true; focusInput=true">show form and
 focus input</button>
<div ng-show="showForm">
  <input type="text" focus-me="focusInput">
  <button class="btn" ng-click="showForm=false">hide form</button>
</div>

app.directive('focusMe', function($timeout) {
  return {
    scope: { trigger: '=focusMe' },
    link: function(scope, element) {
      scope.$watch('trigger', function(value) {
        if(value === true) { 
          //console.log('trigger',value);
          //$timeout(function() {
            element[0].focus();
            scope.trigger = false;
          //});
        }
      });
    }
  };
});

プランカー

ディレクティブのtrigger / focusInputプロパティをリセットする必要があるため、双方向データバインディングには「=」が使用されます。最初のディレクティブでは、「@」で十分でした。また、@を使用すると、@は常に文字列になるため、トリガー値を「true」と比較します。


1
@Joshの "focus"ディレクティブも参照してください:stackoverflow.com/a/14859639/215945 彼は実装に分離スコープを使用しませんでした。
Mark Rajcok、2013

2
@MarkRajcokはこれに興味があります。このバージョンは機能しますがng-model、入力フィールドにを設定すると、isolate スコープが使用されているこのディレクティブを使用すると、モデル値が失われます。Isolate ScopeなしでJoshのバージョンを試しても問題は発生しません。まだ初心者です。違いを理解したいと思います。これはそれを示すプランカーです。
Sunil D.

1
#1はAngularJS 1.0.6で非常にうまく機能することがわかりました。ただし、デバッガーで実行しているときに、モーダルを閉じて再度開くたびに、以前よりもフォーカスを設定する関数の呼び出しが1つ多くなっていることに気付きました。時計のバインドを解除するようにその機能を少し変更しましたがvalue != "true"、これで問題が解決したようです。
アンドリューブラウン

1
だから...ステートフルなページでは、$ watchは$ watchであり、角度のある開発者は$ watchを愛しているので、同じことが起こりました...以下に提案。
Ben Lesh 2013

3
うーん、コードは正しく機能します。適切に実行されていることがわかり、element [0]が正しいコントロールです。ただし、.focus()はフォーカスをトリガーしません。おそらくブートストラップまたは他の何かがこれを妨害していますか?
ソニックソウル

264

(編集:この説明の下に更新されたソリューションを追加しました)

マークRajcokは男だ...と彼の答えは、有効な回答であるが、それはしている欠陥(申し訳ありませんマーク)を有していました...

...ブール値を使用して入力に焦点を合わせてから、入力をぼかし、それを使用して入力に再び焦点を合わせてみてください。ブール値をfalseにリセットしてから、$ digestをリセットして、trueにリセットしない限り、機能しません。式で文字列比較を使用する場合でも、文字列を別の$ digestに変更してから、元に戻す必要があります。(これは、blurイベントハンドラーで対処されています。)

だから私はこの代替ソリューションを提案します:

Angularの忘れられた機能であるイベントを使用します。

JavaScriptは結局のところイベントを愛しています。イベントは本質的に疎結合であり、さらに良いことに、$ digestに別の$ watchを追加することを避けます。

app.directive('focusOn', function() {
   return function(scope, elem, attr) {
      scope.$on(attr.focusOn, function(e) {
          elem[0].focus();
      });
   };
});

したがって、次のように使用できます。

<input type="text" focus-on="newItemAdded" />

そして、あなたのアプリのどこかに...

$scope.addNewItem = function () {
    /* stuff here to add a new item... */

    $scope.$broadcast('newItemAdded');
};

このようなものでいろいろなことができるので、これは素晴らしいことです。1つは、既存のイベントに関連付けることができます。別のこととして、アプリのさまざまな部分に、アプリの他の部分がサブスクライブできるイベントを発行させることで、何かスマートなことを始めます。

とにかく、この種のことは私に「イベントドリブン」を叫びます。Angular開発者として、私たちは$ scope型のペグをイベント型の穴に打ち込むことに真剣に取り組んでいると思います。

それは最善の解決策ですか?私は知らないよ。それ解決策です。


更新されたソリューション

以下の@ShimonRachlenkoのコメントの後、これを行う方法を少し変更しました。ここで、サービスと「裏で」イベントを処理するディレクティブの組み合わせを使用します。

それ以外は、上で概説したのと同じ原則です。

ここに簡単なデモPlunkがあります

使用法

<input type="text" focus-on="focusMe"/>
app.controller('MyCtrl', function($scope, focus) {
    focus('focusMe');
});

ソース

app.directive('focusOn', function() {
   return function(scope, elem, attr) {
      scope.$on('focusOn', function(e, name) {
        if(name === attr.focusOn) {
          elem[0].focus();
        }
      });
   };
});

app.factory('focus', function ($rootScope, $timeout) {
  return function(name) {
    $timeout(function (){
      $rootScope.$broadcast('focusOn', name);
    });
  }
});

3
あなたはへの呼び出しをラップする必要がある$broadcast$timeoutあなたは、コントローラに入る上で動作するようにこれをしたい場合。そうでなければ素晴らしい解決策。
Shimon Rachlenko 2013

@ShimonRachlenko-ありがとう。しかし、$ timeoutの意味がわかりません。コントローラーのコンストラクターが処理されているときにブロードキャストしたい場合は、ただちにブロードキャストします。タイムアウトは何もしませんが、イベントループの後で実行するまでブロードキャストを延期します。
ベンレッシュ

1
はい、そしてディレクティブを初期化するにはそれで十分です。過剰にイベントは、ディレクティブがリスニングを開始する前にブロードキャストされます。これも、ページにアクセスしたときにディレクティブをトリガーする場合にのみ必要です。
Shimon Rachlenko 2013

2
あなたは正しいです。負荷に集中するためにそれを使用していなかったと思います。より堅牢なもので答えを更新します。
Ben Lesh 2013

1
これは、これまでで最もエレガントな「角度のある方法」ソリューションです。この問題に初めて遭遇したときはほとんどコードをコピーしただけですが、そのためのモジュールを作成してくれてうれしいです!正直に言って、コアの角度にそれを入れようと試みる価値があるかもしれないと思います。
Randolpho

241

あなたが本当に必要なのはこれだけであるとき、私は他の答えのいくつかが過度に複雑であることがわかりました

app.directive('autoFocus', function($timeout) {
    return {
        restrict: 'AC',
        link: function(_scope, _element) {
            $timeout(function(){
                _element[0].focus();
            }, 0);
        }
    };
});

使い方は

<input name="theInput" auto-focus>

タイムアウトを使用して、dom内の物をレンダリングします。ゼロであっても、少なくともそれを待機します。これにより、これはモーダルでも機能します


1
これを行うにはいくつかの方法がありますが、本当に簡単で簡単な方法の1つは、スコープ(ここではコントローラー)で、ボタンをクリックしたときにフォーカスするアイテムのIDを設定し、次にディレクティブは単にこれをリッスンします。この場合、特にページ内のどこかにディレクティブを配置する必要はありません(過去にこの種のウォッチャーディレクティブを使用しており、特にフォーカスとスクロールに成功しています)。 jqueryを使用して(これを簡単にするでしょう)、その要素IDを見つけてフォーカスするだけです
ecancil

14
入力がポップアップモーダルにある場合、タイムアウトがゼロのソリューションは機能しません。しかし、10ミリ秒でもこの問題は修正されます
Eugene Fidelin 2014

@ecancil:アプローチが最も簡単なので気に入っていますが、モーダルな外観のアニメーションでは入力の外側でカーソルが点滅するため、IEではタイムアウトを〜500msに設定する必要があります。アニメーションが終了したときにこれを実行するための良い方法がわからないので、500msでブルートフォースします。
Dev93 2014年

データベースからさらにデータをプルする必要がある場合は機能しません。コントローラーがプルデータを完了するまで待機する必要があるため、0の代わりに十分な時間を追加します
Ali Adravi

1
@Adeのようにシンプルでこれを使用したい場合ng-click:ボタンをクリックするng-click="showInput = !showInputと、入力があるとします。次に、実際の入力にを追加しng-if="showInput"ます。ボタンを切り替えると、毎回ディレクティブが再実行されます。私が使ってng-showいたのでこれに問題がありましたが、これは間違ったアプローチです。
JVG 2016

91

HTMLには属性がありますautofocus

<input type="text" name="fname" autofocus>

http://www.w3schools.com/tags/att_input_autofocus.asp


29
残念ながら、これは1度しか機能しません。私はこれをAngular edit in placeの状況で使用しましたが、FirefoxではなくChromeで初めてうまく機能しました。Chromeでは、別のアイテムをクリックしてその場で編集したり、同じアイテムをもう一度クリックしたりしても、フォーカスがなくなります。ドキュメントには、ページの読み込み時に機能することが記載されています。これは、Angularアプリで一度だけ発生します。こんなにシンプルだったら、ビーチに座って20%稼ぐことになるでしょう。
Nocturno 2016年

62

Angularに組み込まれているjqlite機能を使用することもできます。

angular.element('.selector').trigger('focus');


2
jqueryが読み込まれていない場合:angular.forEach(document.querySelectorAll( '。selector')、function(elem){elem.focus();});
Dan Benamy、2014年

29
それをコントローラーに入れるのは悪い習慣ではありませんか?
VitalyB 2014年

2
このjqlite行をコントローラー内に配置するのが悪い習慣である場合、このjqlite行をディレクティブ内に配置する方が良いでしょうか?
スポーツ

3
私はこれを手に入れます:Looking up elements via selectors is not supported by jqLite!
マリアイネスパルナサリ

1
@VitalyB ajax呼び出しの後で要素をぼかす必要がある場合がありました。コントローラー内のコールバックに純粋なJSを1行だけ追加するか、その入力のぼかし専用のディレクティブ全体を作成できます。面倒すぎると感じたので、最初の方法を選びました。
Sebastianb

55

これはうまく機能し、入力制御を集中させるための角度のある方法

angular.element('#elementId').focus()

これはタスクを実行する純粋な角度の方法ではありませんが、構文は角度のスタイルに従います。jqueryは間接的に役割を果たし、Angularを使用してDOMに直接アクセスします(jQLite => JQuery Light)。

必要に応じて、このコードは、要素に直接アクセスできる単純な角度ディレクティブ内に簡単に配置できます。


それがViewModel-appsにとって素晴らしいアプローチであるかどうかはわかりません。Angularでは、ディレクティブを介して行う必要があります。
Agat 2014年

たとえば、誰かがtexbox Aを変更し、ポップアップを表示して、他のtextbox Bにフォーカスを設定する必要がある場合
Sanjeev Singh

1
この使用したとき、私はこのエラーを取得しています:Looking up elements via selectors is not supported by jqLite!
JVG

6
私が知る限りでは、最初に依存関係としてjQueryをロードする必要があります。その場合angular.element、のラッパーになります$() / jQuery()。それがなければ、これは機能せず、基本的にはとにかくjQueryを使用しているだけです(ただし、間違っている場合は修正してください)
JVG

@Jascination:jqLit​​eはjQueryの依存関係を削除するために開発されました。DOMの要素にアクセスするためにjQuery全体を必要としません。ただし、jQueryがインストールされている場合、AngularはjQueryを参照します。これをチェックしてください:docs.angularjs.org/api/angular.element
Sanjeev Singh

31

$ timeoutが要素を作成に集中させる良い方法だとは思いません。これは、組み込みの角度機能を使用して、角度のドキュメントのあいまいな深さから掘り下げた方法です。リンク前機能とリンク後機能の「リンク」属性を「事前」と「投稿」に分割する方法に注意してください。

作業例:http://plnkr.co/edit/Fj59GB

// this is the directive you add to any element you want to highlight after creation
Guest.directive('autoFocus', function() {
    return {
        link: {
            pre: function preLink(scope, element, attr) {
                console.debug('prelink called');
                // this fails since the element hasn't rendered
                //element[0].focus();
            },
            post: function postLink(scope, element, attr) {
                console.debug('postlink called');
                // this succeeds since the element has been rendered
                element[0].focus();
            }
        }
    }
});
<input value="hello" />
<!-- this input automatically gets focus on creation -->
<input value="world" auto-focus />

完全なAngularJSディレクティブドキュメント:https://docs.angularjs.org/api/ng/service/$compile


2
element [0] .focus()を$ timeoutでラップして機能させる必要がありました。
codin

@bbodenmiller私のモーダルにはフェードアウト機能が適用されており、要素が作成されると非表示(100%透明)になるため、ブラウザーはフォーカスの呼び出しをサイレントにブロックします。明らかに数ミリ秒が経過すると、ほぼ透明ですが目に見える入力/ボタンに焦点を合わせることができます。
snowindy

1
ドキュメントによると、「リンク」関数はデフォルトで「postLink」です。また、を参照してください。bennadel.com/blog/...
ジョディ・テイト

17

これが私の元の解決策です:

プランカー

var app = angular.module('plunker', []);
app.directive('autoFocus', function($timeout) {
    return {
        link: function (scope, element, attrs) {
            attrs.$observe("autoFocus", function(newValue){
                if (newValue === "true")
                    $timeout(function(){element[0].focus()});
            });
        }
    };
});

そしてHTML:

<button ng-click="isVisible = !isVisible">Toggle input</button>
<input ng-show="isVisible" auto-focus="{{ isVisible }}" value="auto-focus on" />

それがすること:

ng-showで表示されるようになると、入力をフォーカスします。ここでは$ watchまたは$ onを使用しません。


実際、{{isVisible}}はとにかく時計を作成しているので、「$ watchを使用しない」という記述は正しくありません。
masimplo 14

はい、あなたは正しいと思います。しかし、それはまだそれを行う簡単な方法として機能します。
エドハウラー2014

17

最近のモデルと同じように、双方向バインディングフォーカスディレクティブを記述しました。

次のようなfocusディレクティブを使用できます。

<input focus="someFocusVariable">

trueコントローラの任意の場所でsomeFocusVariableスコープ変数を作成すると、入力がフォーカスされます。入力を「ぼかす」場合は、someFocusVariableをfalseに設定できます。これは、Mark Rajcokの最初の回答に似ていますが、双方向バインディングです。

ここにディレクティブがあります:

function Ctrl($scope) {
  $scope.model = "ahaha"
  $scope.someFocusVariable = true; // If you want to focus initially, set this to true. Else you don't need to define this at all.
}

angular.module('experiement', [])
  .directive('focus', function($timeout, $parse) {
    return {
      restrict: 'A',
      link: function(scope, element, attrs) {
          scope.$watch(attrs.focus, function(newValue, oldValue) {
              if (newValue) { element[0].focus(); }
          });
          element.bind("blur", function(e) {
              $timeout(function() {
                  scope.$apply(attrs.focus + "=false"); 
              }, 0);
          });
          element.bind("focus", function(e) {
              $timeout(function() {
                  scope.$apply(attrs.focus + "=true");
              }, 0);
          })
      }
    }
  });

使用法:

<div ng-app="experiement">
  <div ng-controller="Ctrl">
    An Input: <input ng-model="model" focus="someFocusVariable">
    <hr>
        <div ng-click="someFocusVariable=true">Focus!</div>  
        <pre>someFocusVariable: {{ someFocusVariable }}</pre>
        <pre>content: {{ model }}</pre>
  </div>
</div>

ここにフィドルがあります:

http://fiddle.jshell.net/ubenzer/9FSL4/8/


これが正解です。すべてのユースケースをカバーしています。
Kunal 2017

11

ブートストラッププラグインでAngularを使用する場合:

http://angular-ui.github.io/bootstrap/#/modal

openedモーダルインスタンスのpromiseにフックできます。

modalInstance.opened.then(function() {
        $timeout(function() {
            angular.element('#title_input').trigger('focus');
        });
    });

modalInstance.result.then(function ( etc...

良い!ただし、私の場合、の代わりに$timeoutwith 50msが必要です0
lk_vc 2015年

8

一般的な表現を使用すると便利です。このようにして、入力テキストが有効なときに自動的にフォーカスを移動するなどのことができます

<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">

ディレクティブのコード:

.directive('mooFocusExpression', function ($timeout) {
    return {
        restrict: 'A',
        link: {
            post: function postLink(scope, element, attrs) {
                scope.$watch(attrs.mooFocusExpression, function (value) {

                    if (attrs.mooFocusExpression) {
                        if (scope.$eval(attrs.mooFocusExpression)) {
                            $timeout(function () {
                                element[0].focus();
                            }, 100); //need some delay to work with ng-disabled
                        }
                    }
                });
            }
        }
    };
});

7

ゾンビを復活させたり、自分のディレクティブをプラグインしたりしないでください(これがまさに私がやっていることです)。

https://github.com/hiebj/ng-focus-if

http://plnkr.co/edit/MJS3zRk079Mu72o5A9l6?p=preview

<input focus-if />

(function() {
    'use strict';
    angular
        .module('focus-if', [])
        .directive('focusIf', focusIf);

    function focusIf($timeout) {
        function link($scope, $element, $attrs) {
            var dom = $element[0];
            if ($attrs.focusIf) {
                $scope.$watch($attrs.focusIf, focus);
            } else {
                focus(true);
            }
            function focus(condition) {
                if (condition) {
                    $timeout(function() {
                        dom.focus();
                    }, $scope.$eval($attrs.focusDelay) || 0);
                }
            }
        }
        return {
            restrict: 'A',
            link: link
        };
    }
})();

私は現在このディレクティブを使用していますが、このディレクティブは非常に機能し、一般的な問題を解決し、複雑すぎません。$ timeout-freeソリューションを探してあきらめます。Angular 1.1および1.2のフォーカスは「ロードマップ」にあるというコメントを見つけ続けますが、私は2.xを使用していますが、まだフォーカス管理は行っていません。へえ。
tekHedd

6

最初に、焦点を合わせる公式の方法は1.1ロードマップです。一方、フォーカスの設定を実装するディレクティブを記述できます。

次に、アイテムが表示された後にフォーカスを設定するには、現在回避策が必要です。要素focus()の呼び出しを$timeout

同じコントローラー変更DOM問題がフォーカス、ブラー、選択に存在するため、ng-targetディレクティブを持つことを提案します。

<input type="text" x-ng-model="form.color" x-ng-target="form.colorTarget">
<button class="btn" x-ng-click="form.colorTarget.focus()">do focus</button>

Angular thread here:http : //goo.gl/ipsx4、および詳細についてはこちらのブログ:http : //goo.gl/4rdZa

次のディレクティブは.focus()ng-target属性で指定されたコントローラー内に関数を作成します。(それが作成.blur()し、.select()あまりにも。)デモ:http://jsfiddle.net/bseib/WUcQX/


ロードマップリファレンスの+1。実際、私はただのドキュメントでそれを見た1.2まだ考えられ(不安定docs.angularjs.org/api/ng.directive:ngFocus
エドウィンDalorzo

27
@EdwinDalorzo ngFocusfocusイベントを処理する方法であり、要素にフォーカスを設定する方法ではないようです。
テレクライマー2013年

6

独自のディレクティブを作成する代わりに、JavaScript関数を使用してフォーカスを達成することができます。

ここに例があります。

htmlファイル内:

<input type="text" id="myInputId" />

ファイルのJavaScriptで、たとえばコントローラーで、フォーカスをアクティブ化したい場合:

document.getElementById("myInputId").focus();

9
これは「角度のある方法」ではなく、コントローラーでDOMを操作するように人々にアドバイスしないでください。
smajl

Angularはバニラを追跡したり他のすべてと同期したりできないため、Angularでバニラを使用しないことをお勧めします。
Edgar Quintero

4

ng-clickで制御される単純なフォーカスが必要な場合。

HTML:

<input ut-focus="focusTigger">

<button ng-click="focusTrigger=!focusTrigger" ng-init="focusTrigger=false"></button>

指令:

'use strict'

angular.module('focus',['ng'])
.directive('utFocus',function($timeout){
    return {
        link:function(scope,elem,attr){
            var focusTarget = attr['utFocus'];
            scope.$watch(focusTarget,function(value){
                $timeout(function(){
                    elem[0].focus();
                });
            });
        }
    }
});

4

モーダルでうまく機能するシンプルなもの:

.directive('focusMeNow', ['$timeout', function ($timeout)
{
    return {
        restrict: 'A',

        link: function (scope, element, attrs)
        {


            $timeout(function ()
            {
                element[0].focus();
            });



        }
    };
}])

<input ng-model="your.value" focus-me-now />

私にぴったりです。ありがとう
Alexander

3

postLinkingの装飾された要素にフォーカスを強制するディレクティブを作成するだけです。

angular.module('directives')
.directive('autoFocus', function() {
    return {
        restrict: 'AC',
        link: function(_scope, _element) {
            _element[0].focus();
        }
    };
});

次にあなたのhtmlで:

<input type="text" name="first" auto-focus/> <!-- this will get the focus -->
<input type="text" name="second"/>

これは、モーダルおよびng-ifトグル要素で機能します。postLinkingはHTML処理でのみ発生するため、ng-showでは機能しません。


3

マークとブレッシュは素晴らしい答えを持っています。ただし、Mark'sにはBleshが指摘する欠陥(実装が複雑であることに加えて)があり、Bleshの答えには、本当に必要なすべてがすべてのディレクティブが待機するまでイベントを遅らせます。

つまり、ここで私がやったのはBleshの答えから多くを盗みますが、コントローラーイベントのセマンティクスと「ロード後」のサービスを分離しています。

これにより、特定の要素にフォーカスする以外の目的でコントローラーイベントを簡単にフックでき、必要な場合にのみ「ロード後」機能のオーバーヘッドを発生させることができます。

使用法

<input type="text" focus-on="controllerEvent"/>
app.controller('MyCtrl', function($scope, afterLoad) {
  function notifyControllerEvent() {
      $scope.$broadcast('controllerEvent');
  }

  afterLoad(notifyControllerEvent);
});

ソース

app.directive('focusOn', function() {
   return function(scope, elem, attr) {
      scope.$on(attr.focusOn, function(e, name) {
        elem[0].focus();
      });
   };
});

app.factory('afterLoad', function ($rootScope, $timeout) {
  return function(func) {
    $timeout(func);
  }
});

私(完全な初心者)が理解できる唯一の答え。「afterLoad(notifyControllerEvent);」の代わりに、「notifyControllerEvent()」を使用していました。それ以外の場合は、いくつかのエラーで終了しました。
Vel Murugan S 2015

3

これも使用可能ngModelControllerです。1.6+での作業(古いバージョンではわかりません)。

HTML

<form name="myForm">
    <input type="text" name="myText" ng-model="myText">
</form>

JS

$scope.myForm.myText.$$element.focus();

-

注意:コンテキストによっては、タイムアウト関数をラップする必要があるかもしれません。

NB²:を使用する場合controllerAs、これはほとんど同じです。JSとで置き換えname="myForm"てください。name="vm.myForm"vm.myForm.myText.$$element.focus();


3

おそらく、ES6時代の最もシンプルなソリューションです。

次の1つのライナーディレクティブを追加すると、HTMLの「autofocus」属性がAngular.jsで有効になります。

.directive('autofocus', ($timeout) => ({link: (_, e) => $timeout(() => e[0].focus())}))

これで、次のようなHTML5オートフォーカス構文を使用できます。

<input type="text" autofocus>

@Stephaneはい、そうなります.directive('autofocus', ['$timeout', ($timeout) => ({link: (_, e) => $timeout(() => e[0].focus())})])
Michael Plautz

2

ここでは初心者ですが、このディレクティブを使用してui.bootstrap.modalで機能させることはできませんでした。

directives.directive('focus', function($timeout) {
    return {
        link : function(scope, element) {
            scope.$watch('idToFocus', function(value) {
                if (value === element[0].id) {
                    $timeout(function() {
                        element[0].focus();
                    });
                }
            });
        }
    };
});

$ modal.openメソッドでは、次のようにして、フォーカスを置く要素を示します。

var d = $modal.open({
        controller : function($scope, $modalInstance) {
            ...
            $scope.idToFocus = "cancelaAteste";
    }
        ...
    });

テンプレートにこれがあります:

<input id="myInputId" focus />

2

次のディレクティブは私にとってはトリックです。入力には同じautofocus html属性を使用します。

.directive('autofocus', [function () {
    return {
        require : 'ngModel',
        restrict: 'A',
        link: function (scope, element, attrs) {
            element.focus();
        }
    };
}])

1
jQueryが含まれていない場合、これを実行するとエラーが発生します。代わりにelement [0] .focus()にする必要があります
Ryan M

2

modalInstanceを使用していて、オブジェクトがある場合は、「then」を使用して、モーダルを開いた後にアクションを実行できます。modalInstanceを使用せず、モーダルを開くようにハードコーディングされている場合は、イベントを使用できます。$ timeoutは良い解決策ではありません。

あなたができる(Bootstrap3):

$("#" + modalId).on("shown.bs.modal", function() {
    angular.element("[name='name']").focus();
});

modalInstanceでは、ライブラリを見て、モーダルを開いた後にコードを実行する方法を確認できます。

このように$ timeoutを使用しないでください。$ timeoutは0、1、10、30、50、200以上にすることができます。これは、クライアントコンピューター、およびモーダルを開くプロセスによって異なります。

$ timeoutを使用しないでください。いつフォーカスできるかをメソッドに通知します;)

これがお役に立てば幸いです。:)


2

目的のフォーカス要素がディレクティブテンプレートに挿入されている場合、上記のすべての回答は機能しません。次のディレクティブは、単純な要素またはディレクティブが挿入された要素の両方に適合します(私はそれをtypescript記述しました)。内部のフォーカス可能な要素のセレクターを受け入れます。自己要素にフォーカスする必要がある場合-セレクターパラメーターをディレクティブに送信しないでください。

module APP.Directives {

export class FocusOnLoadDirective implements ng.IDirective {
    priority = 0;
    restrict = 'A';

    constructor(private $interval:any, private $timeout:any) {

    }

    link = (scope:ng.IScope, element:JQuery, attrs:any) => {
        var _self = this;
        var intervalId:number = 0;


        var clearInterval = function () {
            if (intervalId != 0) {
                _self.$interval.cancel(intervalId);
                intervalId = 0;
            }
        };

        _self.$timeout(function(){

                intervalId = _self.$interval(function () {
                    let focusableElement = null;
                    if (attrs.focusOnLoad != '') {
                        focusableElement = element.find(attrs.focusOnLoad);
                    }
                    else {
                        focusableElement = element;
                    }
                    console.debug('focusOnLoad directive: trying to focus');
                    focusableElement.focus();
                    if (document.activeElement === focusableElement[0]) {
                        clearInterval();
                    }
                }, 100);

                scope.$on('$destroy', function () {
                    // Make sure that the interval is destroyed too
                    clearInterval();
                });

        });
    };

    public static factory = ():ng.IDirectiveFactory => {
        let directive = ($interval:any, $timeout:any) => new FocusOnLoadDirective($interval, $timeout);
        directive.$inject = ['$interval', '$timeout'];
        return directive;
    };
}

angular.module('common').directive('focusOnLoad', FocusOnLoadDirective.factory());

}

単純な要素の使用例:

<button tabindex="0" focus-on-load />

内部要素の使用例(通常、テンプレートを使用したディレクティブのような動的に挿入された要素の場合):

<my-directive focus-on-load="input" />

「入力」の代わりに任意のjQueryセレクターを使用できます


2

Mark RajcokのfocusMeディレクティブを編集して、1つの要素で複数のフォーカスを処理できるようにしています。

HTML:

<input  focus-me="myInputFocus"  type="text">

AngularJsコントローラー:

$scope.myInputFocus= true;

AngulaJSディレクティブ:

app.directive('focusMe', function ($timeout, $parse) {
    return {
        link: function (scope, element, attrs) {
            var model = $parse(attrs.focusMe);
            scope.$watch(model, function (value) {
                if (value === true) {
                    $timeout(function () {
                        scope.$apply(model.assign(scope, false));
                        element[0].focus();
                    }, 30);
                }
            });
        }
    };
});

1

より良い解決策を探して見つけられず、代わりに作成する必要があった後、この議論に貢献したいと思います。

基準:1.再利用性を高めるために、ソリューションは親コントローラーのスコープから独立している必要があります。2.いくつかの状態を監視するために$ watchを使用しないでください。これは遅く、ダイジェストループのサイズが大きくなり、テストが困難になります。3. $ timeoutまたは$ scope。$ apply()を使用してダイジェストループをトリガーしないでください。4. input要素は、ディレクティブがオープンで使用されている要素内に存在します。

これは私が最も好きな解決策です:

指令:

.directive('focusInput', [ function () {
    return {
        scope: {},
        restrict: 'A',
        compile: function(elem, attr) {
            elem.bind('click', function() {
                elem.find('input').focus();                
            });
        }        
    };
}]);

HTML:

 <div focus-input>
     <input/>
 </div>

これが誰かの役に立つことを願っています!


htmlの "label"の機能を再作成しただけで、 "div focus-input"を "label"に置き換えて、ディレクティブを取り除くことができます。
2015

1

簡単です。これを試してください

html

<select id="ddl00">  
 <option>"test 01"</option>  
</select>

JavaScript

document.getElementById("ddl00").focus();

これはコンテキスト外では正しいですが、AngularJSのやり方ではありません
CodeMonkey

1

特定の要素にフォーカスを設定したい場合は、以下のアプローチを使用できます。

  1. というサービスを作成しますfocus

    angular.module('application')
    .factory('focus', function ($timeout, $window) {
        return function (id) {
            $timeout(function () {
                var element = $window.document.getElementById(id);
                if (element)
                    element.focus();
            });
        };
    });
  2. 呼び出したい場所からコントローラーに注入します。

  3. このサービスを呼び出します。


0

指令は不要だと思います。HTML idおよびclass属性を使用して必要な要素を選択し、サービスにdocument.getElementByIdまたはdocument.querySelectorを使用してフォーカス(または同等のjQuery)を適用します。

マークアップは、選択用のID /クラスが追加された標準HTML / Angularディレクティブです

<input id="myInput" type="text" ng-model="myInputModel" />

コントローラーはイベントをブロードキャストします

$scope.$emit('ui:focus', '#myInput');

UIサービスではquerySelectorを使用します-複数の一致がある場合(クラスなどにより)、最初の一致のみを返します

$rootScope.$on('ui:focus', function($event, selector){
  var elem = document.querySelector(selector);
  if (elem) {
    elem.focus();
  }
});

$ timeout()を使用してダイジェストサイクルを強制することができます


0

ちょっとコーヒーを入れて。

app.directive 'ngAltFocus', ->
    restrict: 'A'
    scope: ngAltFocus: '='
    link: (scope, el, attrs) ->
        scope.$watch 'ngAltFocus', (nv) -> el[0].focus() if nv
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.