動的なフォームを作成しています。 Field
には値のリストがあります。各値は文字列で表されます。
export class Field{
name: string;
values: string[] = [];
fieldType: string;
constructor(fieldType: string) {this.fieldType = fieldType;}
}
コンポーネントにフィールドに新しい値を追加する関数があります。
addValue(field){
field.values.Push("");
}
HTMLでは、値とボタンがこのように表示されます。
<div id="dropdown-values" *ngFor="let value of field.values; let j=index">
<input type="text" class="form-control" [(ngModel)]="field.values[j]" [name]="'value' + j + '.' + i"/><br/>
</div>
<div class="text-center">
<a href="javascript:void(0);" (click)="addValue(field)"><i class="fa fa-plus-circle" aria-hidden="true"></i></a>
</div>
値の入力にテキストを書き込むとすぐに、入力がフォーカスを失います。フィールドに多くの値を追加し、値入力の1つに文字を書き込むと、入力はフォーカスを失い、文字はすべての入力に書き込まれます。
これは、配列がプリミティブ型、あなたの場合はString
配列の場合に発生します。これはTrackBy
を使用して解決できます。したがって、テンプレートを次のように変更します。
_<div *ngFor="let value of field.values; let i=index; trackBy:trackByFn">
<input type="text" [(ngModel)]="field.values[i]" /><br/>
</div>
<div>
<button (click)="addValue(field)">Click</button>
</div>
_
tsファイルに関数trackByFn
を追加します。これは、値の(一意の)index
を返します。
_trackByFn(index: any, item: any) {
return index;
}
_
これは link です。AngularJSの問題を除き、問題はあなたのものに対応しています。そのページからの最も重要な抜粋:
配列を繰り返し、配列の項目を変更しています(項目は文字列であり、JSのプリミティブであるため、「値で」比較されることに注意してください)。新しいアイテムが検出されるため、古い要素がDOMから削除され、新しい要素が作成されます(明らかにフォーカスが取得されません)。
TrackBy
Angularを使用すると、一意の識別子に従ってどのアイテムが追加(または削除)されたかを追跡し、変更されたもののみを作成または破棄できます。入力フィールドで:)
リンクに見られるように、一意のオブジェクトを含むように配列を変更し、たとえば[(ngModel)]="value.id"
を使用することもできますが、それはおそらく必要なものではありません。
これは、ヘルパー関数を使用してオブジェクトのキーと値を繰り返し処理しているときに起こりました。
_<div *ngFor="let thing of getThings()" [attr.thingname]="thing.key">
... {{ applyThing(thing.value) }}
</div>
_
私のコンポーネントでは、キー/値のペアを含むオブジェクトの配列を返していました。
_export ThingComponent {
...
//this.things = { a: { ... }, b: { ... }, c: { ... } }
public getThings() {
return Object.keys(this.things).map((key) => {
return {key: key, value: this.things[key] }
})
}
}
_
@ AJT_82によって与えられる答えは、明らかに宣伝どおりに機能します。しかし、私の場合、特定の問題はヘルパー関数getThings()
が毎回オブジェクトの新しいリストを返すことでした。内容は同じでしたが、オブジェクト自体は関数への呼び出しごとに再生成され(変更検出中に発生していました)、したがって、変更検出器に対しては異なるIDがあり、モデルが変更されるたびにフォームが再生成されました。
私の場合の簡単な解決策は、getThings()
の結果をキャッシュし、それを反復子として使用することでした。
_<div *ngFor="let thing of cachedThings" [attr.thingname]="thing.key">
... {{ applyThing(thing.value) }}
</div>
_
...
_export ThingComponent {
public cachedThings = getThings()
...
//this.things = { a: { ... }, b: { ... }, c: { ... } }
private getThings() {
return Object.keys(this.things).map((key) => {
return {key: key, value: this.things[key] }
})
}
}
_
cachedThings
を変更する必要がある場合、変更検出器が再レンダリングをトリガーするように、手動で更新する必要があります。