770

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

より具体的な要件:

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

で最初の要件を達成しようとしましたautofocusが、これはModalを初めて開いたときにのみ機能し、特定のブラウザーでのみ機能します(たとえば、Firefoxでは機能しません)。

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

4

33 に答える 33

591
  1. Modal が開かれたら、この Modal 内の事前定義された <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 月: 元の Isolate スコープ ディレクティブを使用し、埋め込み入力フィールド (つまり、モーダルの入力フィールド) に問題がある人を数人見てきました。新しいスコープ (または新しい子スコープ) を持たないディレクティブは、痛みの一部を軽減するはずです。そのため、上記の回答を更新して、分離スコープを使用しないようにしました。以下は元の答えです:

分離スコープを使用した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;
          //});
        }
      });
    }
  };
});

プランカー

ディレクティブでトリガー/フォーカス入力プロパティをリセットする必要があるため、「=」は双方向のデータバインディングに使用されます。最初のディレクティブでは、'@' で十分でした。また、「@」を使用すると、@ は常に文字列になるため、トリガー値を「true」と比較することに注意してください。

于 2013-02-12T16:23:14.677 に答える
92

HTML には属性がありますautofocus

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

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

于 2015-09-29T12:43:52.480 に答える
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 を使用しません。

于 2014-06-11T20:58:50.740 に答える
17

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

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

<input focus="someFocusVariable">

コントローラの任意の場所でsomeFocusVariable スコープ変数を作成するtrueと、入力がフォーカスされます。入力を「ぼかし」たい場合は、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/

于 2013-07-19T06:49:14.940 に答える
11

Bootstrap プラグインで 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...
于 2015-03-03T15:32:25.840 に答える
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
                        }
                    }
                });
            }
        }
    };
});
于 2015-04-30T09:15:27.673 に答える
5

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();
                });
            });
        }
    }
});
于 2014-02-17T18:06:26.853 に答える
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 />
于 2016-01-13T15:35:47.657 に答える
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);
  }
});
于 2014-02-18T23:14:30.600 に答える
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"/>

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

于 2013-12-26T16:25:20.510 に答える
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);
                }
            });
        }
    };
});
于 2014-07-21T11:53:15.963 に答える
2

次のディレクティブは私にとってはうまくいきました。入力には同じ autofocus html 属性を使用します。

.directive('autofocus', [function () {
    return {
        require : 'ngModel',
        restrict: 'A',
        link: function (scope, element, attrs) {
            element.focus();
        }
    };
}])
于 2015-08-06T03:41:17.050 に答える
2

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

  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. このサービスを呼び出します。

于 2018-02-13T11:52:08.353 に答える
1

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

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

これは私が最も気に入ったソリューションです。

指令:

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

これが誰かを助けることを願っています!

于 2015-02-18T13:10:00.713 に答える
0

以下のディレクティブを使用して、html 入力でブール値を取得し、それにフォーカスすることができます...

//js file
angular.module("appName").directive("ngFocus", function () {
       return function (scope, elem, attrs, ctrl) {
             if (attrs.ngFocus === "true") {
                 $(elem).focus();
             }
             if (!ctrl) {
                 return;
             }
       elem.on("focus", function () {
            elem.addClass("has-focus");
            scope.$apply(function () {
                ctrl.hasFocus = true;
            });
        });
    };
});

<!-- html file -->
<input type="text" ng-focus="boolValue" />

コントローラーの関数を ngFocus ディレクティブ値に設定することもできます。以下のコードに注意してください...

<!-- html file -->
<input type="text" ng-focus="myFunc()" />


//controller file
$scope.myFunc=function(){
      if(condition){
          return true;
      }else{
          return false;
      }
}

このディレクティブは、html ページのレンダリング時に発生します。

于 2016-12-29T13:10:42.887 に答える
0

タイムアウトに依存することが良い考えかどうかはわかりませんが、このコードは angularjs が DOM を更新した後に実行されるため、これは ng-repeat で機能するため、すべてのオブジェクトがそこにあることを確認してください。

myApp.directive('onLastRepeat', [function () {
        return function (scope, element, attrs) {
            if (scope.$last) setTimeout(function () {
                scope.$emit('onRepeatLast', element, attrs);
            }, 1);
        };
    }]);
    //controller for grid
    myApp.controller('SimpleController', ['$scope', '$timeout', '$http', function ($scope, $timeout, $http)
    {
        var newItemRemoved = false;
        var requiredAlert = false;
        //this event fires up when angular updates the dom for the last item
        //it's observed, so here, we stop the progress bar
        $scope.$on('onRepeatLast', function (scope, element, attrs) {
            //$scope.complete();
            console.log('done done!');
            $("#txtFirstName").focus();
        });
    }]);
于 2015-02-06T20:40:40.107 に答える
0

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

マークアップは、選択用の id/class が追加された標準の 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() を使用してダイジェスト サイクルを強制することもできます

于 2014-03-30T23:37:48.897 に答える
0

要素の任意のアクションをプログラムで呼び出します: click()、focus()、select()...

使用法:

<a href="google.com" auto-action="{'click': $scope.autoclick, 'focus': $scope.autofocus}">Link</a>

指令:

/**
 * Programatically Triggers given function on the element
 * Syntax: the same as for ng-class="object"
 * Example: <a href="google.com" auto-action="{'click': autoclick_boolean, 'focus': autofocus_boolean}">Link</a>
 */
app.directive('focusMe', function ($timeout) {
    return {
        restrict: 'A',
        scope: {
            autoAction: '<',
        },
        link: function (scope, element, attr) {
            const _el = element[0];
            for (const func in scope.autoAction) {
                if (!scope.autoAction.hasOwnProperty(func)) {
                    continue;
                }
                scope.$watch(`autoAction['${func}']`, (newVal, oldVal) => {
                    if (newVal !== oldVal) {
                        $timeout(() => {
                            _el[func]();
                        });
                    }
                });
            }

        }
    }
});

この質問に対処するには、初期化時に変数を (できれば) コントローラーで、または ng-init として設定します。

 <input ng-init="autofocus=true" auto-action="{'focus': autofocus}">
于 2018-10-19T12:43:55.803 に答える