Angular.js: <input/>ng-modelがng-repeat配列を直接参照すると、フォーカスが失われます

作成日 2015年11月18日  ·  10コメント  ·  ソース: angular/angular.js

私が持っているシンプルな<input>内側<div ng-repeat...">

文字を入力するとすぐに、 <input>フォーカスが失われます。 入力を続けるには、最初に入力したい_each_文字の入力領域内をクリックする必要があります。

問題を示すng-repeatコードの本質は次のとおりです。

<div ng-repeat="item in items">
    <input ng-model="items[$index]">
</div>

しかし、 <input>内側ng-repeat範囲が、直接参照していませんng-repeat配列を、罰金に動作します-私は一日中データを入力することができます。 例えば:

<div ng-repeat="item in items">
    <input ng-model="george">
</div>

注:この問題は、items配列の$index番目の要素を直接参照しているng-model明らかに関連しています。 私の推測では、コレクションの$ watchがトリガーされ、フォーカスが失われます。

問題を示すcodepenは次のとおりです。
http://codepen.io/djmarcus/pen/bVZGvj

これが蒸留です:

    <div ng-controller="myCtrl">
        <div ng-repeat="item in items">
          <div>This fails</div>
          <div layout="row" layout-align="start center">
            <input ng-model="items[$index]"  label=""> 
          </div>
        </div>

        <div ng-repeat="item in items">
          <div>This works</div>
          <div layout="row" layout-align="start center">
            <input ng-model="george"  label=""> 
          </div>
        </div>

        <div>This works (its outside of ng-repeat) </div>
        <input ng-model="harvey" label="">
    </div>
ngRepeat investigation

最も参考になるコメント

これは予想される動作だと思います。

@Narretzが述べたように、配列を繰り返し、配列の項目を変更しています(項目は文字列であり、JSのプリミティブであるため、「値で」比較されることに注意してください)。 新しいアイテムが検出されると、古い要素がDOMから削除され、新しい要素が作成されます(明らかにフォーカスが取得されません)。

目的の動作を実現するには、いくつかの方法があります。

  1. ngRepeatの子スコープで作成されたローカルitem変数を使用します。実際、この場合、双方向バインディングでは機能しません。 オプション2または3を使用します。

html <div ng-repeat="item in items"> <input type="text" ng-model="item" /> </div>

  1. track by $index使用します(ユースケースに適している場合、つまり、アイテムが再注文されないことがわかっている場合):

html <div ng-repeat="item in items track by $index"> <input type="text" ng-model="items[$index]" /> </div>

  1. 文字列をオブジェクトにラップします。 例: items = [{value: 'string1'}, {value: 'string2'}, ...]

html <div ng-repeat="item in items"> <input type="text" ng-model="items[$index].value" /> </div>

このデモペンでは、3つのソリューションすべての動作を確認できます。

全てのコメント10件

関連する問題がどこかに浮かんでいると思いますが、それは繰り返される要素が移動され、フォーカスが失われたためです。 この例では、DOMの並べ替えは発生しないはずなので、調査が必要です。

これは予想される動作だと思います。

@Narretzが述べたように、配列を繰り返し、配列の項目を変更しています(項目は文字列であり、JSのプリミティブであるため、「値で」比較されることに注意してください)。 新しいアイテムが検出されると、古い要素がDOMから削除され、新しい要素が作成されます(明らかにフォーカスが取得されません)。

目的の動作を実現するには、いくつかの方法があります。

  1. ngRepeatの子スコープで作成されたローカルitem変数を使用します。実際、この場合、双方向バインディングでは機能しません。 オプション2または3を使用します。

html <div ng-repeat="item in items"> <input type="text" ng-model="item" /> </div>

  1. track by $index使用します(ユースケースに適している場合、つまり、アイテムが再注文されないことがわかっている場合):

html <div ng-repeat="item in items track by $index"> <input type="text" ng-model="items[$index]" /> </div>

  1. 文字列をオブジェクトにラップします。 例: items = [{value: 'string1'}, {value: 'string2'}, ...]

html <div ng-repeat="item in items"> <input type="text" ng-model="items[$index].value" /> </div>

このデモペンでは、3つのソリューションすべての動作を確認できます。

@gkalpakに感謝します。 あなたは正しいです、行動は期待されています。

私はオプション#3を使用することになりました。 問題を明確にしてくれてありがとう(後から考えると明らかです)。

Angularの「落とし穴」の問題に関するドキュメントがあれば助かります。これはそのリストの最有力候補です。

TBH、私はあなたがオプション#1に従うことを期待します。 このように使用するのは非常に一般的です-なぜそれを使用できないのだろうか(特定の理由がある場合)。

オプション#1(codepenでコード化されている)は、私が最初に使用していたものです。 あなたが上で与えた理由のために(少なくとも私がcodepenでそれを試してみると)それは機能しません...おそらくあなたはcodepenで何か違うことを意味しましたか?

それにもかかわらず、オプション#3は私のコードに最も密接に関連しています。 私がng-repeatしている配列は、実際にはオブジェクトの配列(単純な文字列ではありません)であり、プロパティの1つに関心があります。したがって、オプション#3が適しています。

[オプション#1]が機能しない(少なくともcodepenで試してみると)

おっと、あなたは正しいです。 オプション#1は、 ngModel介した双方向バインディングには適していません。
(将来の読者の混乱を避けるために、以前のコメントを更新しました。)

@gkalpakによるアプローチ#2で問題が修正されました。 しかし、Angular2ではこれが必要でした。 解決してくれてありがとう。

このスレッドに出くわし、Angular 2で解決策を探している場合、解決策は非常に簡単です。
配列との双方向バインディングの代わりに、プロパティをバインドし、「input」ではなく「change」イベントを使用して変更イベントを処理するだけです。

例:

// Instead of writing
<div *ngFor="let param of params.value; let id = index;">
    <input type="text" placeholder="0" [(ngModel)]="params.value[id]">
</div

// Write
<div *ngFor="let param of params.value; let id = index;">
    <input type="text" placeholder="0" [ngModel]="params.value[id]" (change)="onValueUpdate($event, id)">
</div>

onValueUpdate関数で値を更新します。

変更イベントは入力からぼかしたときにのみトリガーされるため、エラーに直面することはもうありません。

ありがとう@gkalpak
それは私のために働いた。 私はoption3に行き着きました。 Angular4でも機能しました

このページは役に立ちましたか?
0 / 5 - 0 評価