私が持っているシンプルな<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>
関連する問題がどこかに浮かんでいると思いますが、それは繰り返される要素が移動され、フォーカスが失われたためです。 この例では、DOMの並べ替えは発生しないはずなので、調査が必要です。
これは予想される動作だと思います。
@Narretzが述べたように、配列を繰り返し、配列の項目を変更しています(項目は文字列であり、JSのプリミティブであるため、「値で」比較されることに注意してください)。 新しいアイテムが検出されると、古い要素がDOMから削除され、新しい要素が作成されます(明らかにフォーカスが取得されません)。
目的の動作を実現するには、いくつかの方法があります。
ngRepeat
の子スコープで作成されたローカルitem
変数を使用します。html
<div ng-repeat="item in items">
<input type="text" ng-model="item" />
</div>
track by $index
使用します(ユースケースに適している場合、つまり、アイテムが再注文されないことがわかっている場合):html
<div ng-repeat="item in items track by $index">
<input type="text" ng-model="items[$index]" />
</div>
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でも機能しました
最も参考になるコメント
これは予想される動作だと思います。
@Narretzが述べたように、配列を繰り返し、配列の項目を変更しています(項目は文字列であり、JSのプリミティブであるため、「値で」比較されることに注意してください)。 新しいアイテムが検出されると、古い要素がDOMから削除され、新しい要素が作成されます(明らかにフォーカスが取得されません)。
目的の動作を実現するには、いくつかの方法があります。
実際、この場合、双方向バインディングでは機能しません。 オプション2または3を使用します。ngRepeat
の子スコープで作成されたローカルitem
変数を使用します。html <div ng-repeat="item in items"> <input type="text" ng-model="item" /> </div>
track by $index
使用します(ユースケースに適している場合、つまり、アイテムが再注文されないことがわかっている場合):html <div ng-repeat="item in items track by $index"> <input type="text" ng-model="items[$index]" /> </div>
items = [{value: 'string1'}, {value: 'string2'}, ...]
:html <div ng-repeat="item in items"> <input type="text" ng-model="items[$index].value" /> </div>
このデモペンでは、3つのソリューションすべての動作を確認できます。