2017-02-19 33 views
17

私は動的フォームを作成しています。 Fieldには値のリストがあります。各値は文字列で表されます。Angular2入力が変わると動的入力フィールドのフォーカスが失われます

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> 

値の入力にテキストを書き込むと、入力はフォーカスを失います。 フィールドに多くの値を追加し、値入力に文字を書き込むと、入力はフォーカスを失い、文字はすべての入力に書き込まれます。

答えて

41

これは、配列がプリミティブ型の場合に発生します。ケースでは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ファイル内の値の(ユニーク)indexを返す関数trackByFnを、追加します。

trackByFn(index: any, item: any) { 
    return index; 
} 

これはおよそlinkです問題はAngularJSの問題を除いて同じ問題ですが、問題はあなたの問題に相当します。そのページからの最も重要な抜粋:

あなたは配列の項目を変更しています(項目はJSのプリミティブであり、したがって値によって比較される文字列です)。新しいアイテムが検出されるので、古い要素はDOMから削除され、新しい要素が作成されます(明らかにフォーカスを取得しません)。

TrackByで角度はあなたの入力フィールドにフォーカスを失わないことを意味する変更のみ物事を一意の識別子に応じて追加(または削除)されたアイテムを追跡し、作成したり、破壊することができます:)

リンクに表示されているように、一意のオブジェクトを含むように配列を変更して、例えば[(ngModel)]="value.id"を使用することもできますが、これは必要ではないかもしれません。私は、キー/値のペアを含むオブジェクトの配列を返していました、私のコンポーネントで

<div *ngFor="let thing of getThings()" [attr.thingname]="thing.key"> 
    ... {{ applyThing(thing.value) }} 
</div> 

::私はヘルパー関数を使用して、オブジェクトのキーと値を反復処理されたとき、これが私に起こっていた

+0

私の場合は、プリミティブの配列に対して反復処理をしていませんでしたが、オブジェクトの配列(実際はFormArray)は同じ問題を抱えています。 でも、私は@ AJT_82の提案に続き、それは問題を解決しました – Thisisalexis

+0

@AlexisJoséBravoLloveraうれしいことを聞いてうれしくて助けになりました!私たちが実際にオブジェクトを扱っているので、これと同じ理由で、formarrayで何か起きているようですが、その理由はわかりません。https://stackoverflow.com/questions/44445676/add-to-反応の初期形態のアレイ角 – Alex

0

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> 

... cachedThingsが変化することが必要になる場合があります場合には

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] } 
    }) 
    } 
} 

、それを変更検出器が再レンダリングをトリガーするように、手動で更新する必要があります。

関連する問題