web-dev-qa-db-ja.com

Angular2ダイナミック入力フィールドは、入力が変更されるとフォーカスを失います

動的なフォームを作成しています。 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つに文字を書き込むと、入力はフォーカスを失い、文字はすべての入力に書き込まれます。

35
Servietsky

これは、配列がプリミティブ型、あなたの場合は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"を使用することもできますが、それはおそらく必要なものではありません。

91
AJT_82

これは、ヘルパー関数を使用してオブジェクトのキーと値を繰り返し処理しているときに起こりました。

_<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を変更する必要がある場合、変更検出器が再レンダリングをトリガーするように、手動で更新する必要があります。

0
t.888