19

私はこの角度コードを持っています:

<div class="element-wrapper" ng-repeat="element in elements">
  <div class="first-wrapper">
     <div class="button" ng-click="doSomething(element,$event)">{{element.name}}</div>   
  </div>
  <div class="second-wrapper">
    <input type="text" value="{{element.value}}">    
  </div>
</div>

私がしたいこと:ユーザーがボタンをクリックすると、入力要素がフォーカスされます。

ボタン要素をクリックしてフォーカスした後、入力要素を見つけるにはどうすればよいですか?

次のような関数を実行できます。

function doSomething(element,$event) {
  //option A - start manipulating in the dark:
  $event.srcElement.parentNode.childNodes[1]

  //option B - wrapping it with jQuery:
   $($event.srcElement).closest('.element-wrapper').find('input').focus();
}

どちらも機能しません-それを行うためのより良いAngularの方法はありますか? jQuery で.closest()やasなどの関数を使用していますか?.find()

アップデート:

このハックが機能していることがわかりました(ただし、それでも正しい解決策とは思えません)

function doSomething(element,$event) {
   setTimeout(function(){
     $($event.srcElement).closest('.element-wrapper').find('input').focus();
   },0)
}

私はそれを setTimeout でラップしているので、Angular がすべての操作を終了した後、input 要素に焦点を合わせます。

4

7 に答える 7

38

DOM 操作は、コントローラーではなくディレクティブで行う必要があります。ディレクティブを定義focusInputしてボタンで使用します。

<div class="button" focus-input>{{element.name}}</div>   

指令:

app.directive('focusInput', function($timeout) {
  return {
    link: function(scope, element, attrs) {
      element.bind('click', function() {
        $timeout(function() {
          element.parent().parent().find('input')[0].focus();
        });
      });
    }
  };
});

プランカー

jqLit ​​eは DOM トラバーサル メソッドに関してかなり制限されているため、parent().parent(). jQuery またはいくつかの JavaScript メソッドを使用したい場合があります。

すでにわかっているように、ブラウザがレンダリングした後 (つまり、クリック イベントの処理が終了した後) にメソッドが呼び出される$timeoutようにするために必要です。focus()

find('input')[0]DOM 要素へのアクセスを提供し、 ( jQuery を必要とするのではfocus()なく) JavaScript メソッドを使用できるようにします。find('input').focus()

于 2013-03-20T16:35:23.250 に答える
10

私は最近AngularJSを見てきましたが、同様の状況に遭遇しました.

Todo サンプル アプリケーションをメインの角度ページから更新して、todo 項目をダブルクリックしたときに「編集」モードを追加する作業をしていました。

モデル/状態ベースのアプローチを使用して問題を解決できました。アプリケーションが同様の方法で動作する場合 (モデルのいくつかの条件が true のときにフィールドにフォーカスを設定したい場合)、これもうまくいく可能性があります。

私のアプローチは、ユーザーが todo ラベルをダブルクリックしたときにmodel.editingプロパティを設定するtrueことです。これにより、編集可能な入力が表示され、通常の編集不可能なラベルとチェックボックスが非表示になります。focusInputまた、同じプロパティを監視しmodel.editing、値が変更されたときにテキスト フィールドにフォーカスを設定するというカスタム ディレクティブもあります。

<li ng-repeat="todo in todos">

    <div>
        <!-- Regular display view. -->
        <div ng-show="todo.editing == false">
            <label class="done-{{todo.done}}" ng-dblclick="model.editing = true">
                <input type="checkbox" ng-model="todo.done"/>{{todo.text}}
            </label>
        </div>

        <!-- Editable view. -->
        <div ng-show="todo.editing == true">
            <!--
                - Add the `focus-input` directive with the statement "todo.editing == true".
                  This is the element that will receive focus when the statement evaluates to true.

                - We also add the `todoBlur` directive so we can cancel editing when the text field loses focus.
            -->
            <input type="text" ng-model="todo.text" focus-input="todo.editing == true" todo-blur="todo.editing = false"/>
        </div>
    </div>

</li>

focusInputいくつかの条件が に評価されたときに現在の要素にフォーカスを設定するディレクティブは次のtrueとおりです。

angular.module('TodoModule', [])
    // Define a new directive called `focusInput`.
    .directive('focusInput', function($timeout){
        return function(scope, element, attr){

            // Add a watch on the `focus-input` attribute.
            // Whenever the `focus-input` statement changes this callback function will be executed.
            scope.$watch(attr.focusInput, function(value){
                // If the `focus-input` statement evaluates to `true`
                // then use jQuery to set focus on the element.
                if (value){
                    $timeout(function(){
                        element.select();
                    });
                }
            });

        };
    })
    // Here is the directive to raise the 'blur' event.
    .directive('todoBlur', [
        '$parse', function($parse){
            return function(scope, element, attr){

                var fn = $parse(attr['todoBlur']);
                return element.on('blur', function(event){

                    return scope.$apply(function(){
                        return fn(scope, {
                            $event: event
                        });
                    });

                });

            };
        }
    ]);
于 2013-06-29T01:51:25.047 に答える
4

簡単な答えを提供するためだけに、アカウントを作成する必要がありました。

//Add a bool to your controller's scope that indicates if your element is focused
... //ellipsis used so I don't write the part you should know
$scope.userInputActivate = false;
...
//Add a new directive to your app stack
...
.directive('focusBool', function() { 
    return function(scope, element, attrs) {
        scope.$watch(attrs.focusBool, function(value) {
            if (value) $timeout(function() {element.focus();});
        });
    }
})
...

<!--Now that our code is watching for a scope boolean variable, stick that variable on your input element using your new directive, and manipulate that variable as desired.-->
...
<div class="button" ng-click="userInputActivate=true">...</div>
...
<input type="text" focus-Bool="userInputActivate">
...

入力を使用していないときは、必ずこの変数をリセットしてください。元に戻すのに十分なほど簡単な ng-blur ディレクティブを追加するか、それを false にリセットする別の ng-click イベントを追加できます。false に設定すると、次回の準備が整います。これは、見つけるのに問題がある場合に備えて、私が見つけた ng-blur ディレクティブの例です。

.directive('ngBlur', ['$parse', function($parse) {
    return function(scope, element, attr) {
        var fn = $parse(attr['ngBlur']);
        element.bind('blur', function(event) {
        scope.$apply(function() {
            fn(scope, {$event:event});
        });
    });
    }
}]);
于 2013-07-23T20:14:10.957 に答える
0

入力を見つけるには、ID を追加し<input id="input{{$index}}" .. />、ngRepeat インデックスをパラメータとして関数に渡しますng-click="doSomething(element,$event, $index)"

 <div class="element-wrapper" ng-repeat="element in elements">
  <div class="first-wrapper">
     <div class="button" ng-click="doSomething(element,$event, $index)">{{element.name}}</div>   
  </div>
  <div class="second-wrapper">
    <input id="input{{$index}}" type="text" value="{{element.value}}">    
  </div>
</div>   

$timeoutDOM レンダリングの最後まで待機するためのゼロ遅延で関数を使用します。getElementById次に、関数内で入力を見つけることができます$timeout$timeoutコントローラーに追加することを忘れないでください。

.controller("MyController", function ($scope, $timeout)
{
  $scope.doSomething = function(element,$event, index) {
    //option A - start manipulating in the dark:
    $event.srcElement.parentNode.childNodes[1]

    $timeout(function () 
    {
      document.getElementById("input" + index).focus();
    });
  }
});
于 2016-06-20T18:10:24.030 に答える
0

.closest() メソッドを使用するには、プロトタイプ継承メカニズム fox expand angular の機会を適用することをお勧めします。ちょうどこのような:

angular.element.prototype.closest = (parentClass)->
  $this = this
  closestElement = undefined
  while $this.parent()
    if $this.parent().hasClass parentClass
      closestElement = $this.parent()
      break
    $this = $this.parent()
  closestElement

マークアップ:

<span ng-click="removeNote($event)" class="remove-note"></span>

使用法:

 $scope.removeNote = ($event)->
    currentNote = angular.element($event.currentTarget).closest("content-list_item") 
    currentNote.remove()
于 2015-11-21T01:34:40.537 に答える