2017-04-20 13 views
8

私の角(4 + Typescript)プロジェクトの中で私はすでに準備されたコンポーネントを使っていました(ControlValueAccessorを拡張する方法は同じなのですが、 ng2-select)は、より良いUXとより良い外観のために欲しかった。それを私が見た反応的なフォームを使用している私のフォームコンポーネントに含めた後、私は、フォームのコントロールのために、選択されたアイテムを管理するために準備されたコンポーネントの内部で使用されるクラスSelectItemに基づいてオブジェクトを取得します。提出と値の変更の角度4 ControlValueAccessorの値

// console.log(this.myForm.values) 
Object { 
    txtInput: 'value', 
    // ... 
    preparedComponent: SelectItem { // <-- 
     id: '1', 
     text: 'Chosen item' 
    } 
} 

コンポーネントは基本的に標準の選択制御のためだけの交換であるので、私は、文字列として形成された選択項目のIDが返されますことを期待していた - このように:私の後

// console.log(this.myForm.values) 
Object { 
    txtInput: 'value', 
    // ... 
    preparedComponent: '1' // <-- 
} 

を実際にControlValueAccessorが何であるかを学び、それがどのように機能するか、私は提出時に戻ってくるものの方法を変更しました(あるいは、項目変更 - onChange)を項目のIDに追加します。この問題は、(インスタンスの追加時に)空の値の代わりにフォームのコントロールに事前定義された値を設定する(インスタンスの編集時に)まで、しばらくの間解決されました。今回は、writeValueが、定義済みの値として送信された内容に基づいてフォームコントロールに値を割り当てていることがわかりました。だから... ...私は

Object { 
    id: '1', 
    text: 'Chosen item' 
} 

...として所定の値を送信した場合に、これはまた、単に上記の最初のコード例のように提出上のオブジェクトの値でした。私はwriteValueが呼び出された直後に、onChangeで制御に正しい値を割り当てるためにこれを回避する方法を作った。これは実際にそれをやっての不適切な方法でしたが、私はそれ以外のものを考え出したことができませんでした:

public writeValue(val: any): void { 
    this.selectedItems = val; // val is for example Object { id: '1', text: 'Chosen item' } 

    setTimeout(() => { 
     this.onChange(val.id); // just an example of emitted value, there should be some checks val is object and id exists in real code 
    }, 0); 
} 

そしてまた、私の知る限り、コントロールのvalueChangesを形成するためにサブスクライブして起動しなかったとして働いていたことを。問題は、準備されたコンポーネントにあらかじめ定義された値を割り当てるたびに、{ emitEvent: false }を使用していても、サブミット後に使用された値が放出されることです。

これは、準備されたコンポーネントで何らかの形で処理したいことです。送信時に適切な値を取得したいからです。値が実際に変更されていない限り、サブスクライバに変更を送信したくありません。あらかじめ定義された値として置き換えられます。どのようにこれを処理するか考えていただければ幸いです。

+0

私はちょっとこの正確なプロセスを行った。私はあなたが持っている正確な問題を理解しているかどうかは確かではありません。 – Amit

+0

問題は主に 'writeValue'の中の' onChanges'です。最初は 'setTimeout'が実際に回避策としてやっていた最後のもので、第2に、定義済みの値で初期化されたときに変更イベントが発生するからです。理想的には入力と出力の値が分離されます。入力はオブジェクトを受け取り、出力は選択されたオブジェクトのIDを返します。したがって、デフォルトの動作として期待されるものではないので、値の初期化時に変更を発行する必要はありません( '{emitEvent:false} 'の場合は' setValue'の 'set'に' reset'を指定します)Angularはイベントを送出しません時chaning値)。 – user1257255

+1

ng2-select(btwはほとんど維持されていません) "fighting" – Amit

答えて

2

私はこれを正しく理解しているかどうかはわかりませんが、私はそれを試してみたいと思います。

{ 
    id: string, 
    text: string 
} 

しかし、あなたは、コンポーネントの出力は、選択した項目の単なる文字列IDになりたい:

あなたは、コンポーネントの入力は、以下のタイプであることにしたいです。

私は、このデータフローが少し厄介であると主張します。初期化中はpreparedComponentobjectですが、アイテムが選択されたときにはstringに変更します。型の安全性の問題とは別に、それは直感的ではないと感じています。

比較のために、ngModelおよびテキスト入力でこれをやって想像:

<input type="text" [(ngModel)]="preparedComponent" /> 

はあなたがオブジェクトを渡すことを期待する、と文字列のユーザータイプを取り戻しますか?おそらくそうではありません。


ただし、何らかの理由でこのようになっている必要があるとします。 ng2-selectの実装をControlValueAccessorに変更するか、ControlValueAccessorを実装し、ng2-selectを実装する独自のコンポーネントを作成することで進めました。 (私はあなたの質問でこれらのうちのどれをしているのか分からない)。アイテムが選択されるとthis.onChange(val.id)にコールされ、親コンポーネントが文字列IDで更新されます。

次に、別の問題に気付きました。これは、選択した値を事前定義しておくと、初期化中に変更イベントが発生するということです(ng2-select)。ユーザーがまだ選択コントロールと対話していないため、これは奇妙です。あなたはemitEvent: falseでフォームコントロールのsetValueを呼び出すことによってpreparedComponentを初期化しようとしましたが、データを初期化したときに変更イベントが発生するのを防ぐことができたので、これはうまくいかなかったと思います。ng2-selectは、すぐに。

代わりにng2-selectの最初の更新が親コンポーネントを新しいオブジェクトに更新し、(setTimeoutを使用して)実際に必要な文字列IDで上書きするまで待ってこの問題を回避しました。これにより、文字列でpreparedComponentが最新の状態に保たれますが、ユーザーがコントロールとやり取りしなかった場合でも変更イベントの発生の問題は解決しません。 (ちなみに、ng2-selectを独自のコンポーネントでラップしている場合は、ng2-selectが新しい情報を通知したときにthis.onChange(val.id)を呼び出す別の関数をまだ持っていないので、なぜこの部分をsetTimeoutの部分にする必要があるのか​​分かりません。私は前の段落で述べたように、アイテムを選択)


私はあなたが直接ng2-selectを変更、または独自のコンポーネントでそれをラップしているかどうかを言うことができないので:?

あなたがng2-selectを変更する場合、なぜwriteValueメソッドを見つけてイベントを発行するコードを削除しないのですか?この方法では、値を事前定義するときにDOMを更新しますが、値を上書きしません。

あなたはなぜちょうどng2-selectは、あなたがそれを無視することができますので、イベントを発生しようとしている場合にはフラグを格納するために、あなたのwriteValue方法を変更していない、独自のコンポーネントでng2-selectをラップしている場合:

private: ignoreSelectedEvent = false; 

public writeValue(val: any): void { 
    this.ignoreSelectedEvent = true; 

    // Update ng2-select, which will cause an event to fire 
} 

そして中新しい選択項目に反応するあなたの機能:それは書き込みによって処理された初期値として制御コンポーネントに異なる値の型を送信することが可能です場合

if (this.ignoreSelectedEvent) { 
    this.ignoreSelectedEvent = false; 

    return; 
} 

// Update the model with the string ID 

this.onChange(val.id); 
0

は基本的に質問が求めていました値のメソッド。この場合、選択されているタイプ(単一の値または複数の値)に応じて、値を文字列IDまたは文字列IDの配列に変換する必要があります。フランク氏の答えによると、これをやってsetTimeoutの回避策を使ってonChangeを呼び出すのは少し面倒です。

解決策は、オブジェクトをID/IDの配列に変換した後に、コントロールコンポーネントがonChangeに返す値に初期値を設定することです。コンポーネント自体は、送信されるID/IDに応じて、使用可能なすべてのアイテムから適切なオブジェクトを選択する必要があります。

関連する問題