2016-03-28 4 views
15

liアイテムをクリックするとモデルを設定するカスタム選択コンポーネントがありますが、モデルを変更するたびに手動でthis.modelChange.next(this.model)を呼び出すので、避けたいと思うものはかなり乱雑です。角度2でモデルが変化するたびに関数を呼び出す方法は?

$scope.$watchのようなものがあり、値が変わるのを見て、それが起こるたびにthis.modelChange.next(this.model)を呼び出すのが私の質問です。

私はObservablesについて読んできましたが、私が見ているすべての例は外部APIへの非同期要求であるため、単純な値としてどのように使用されるのか分かりません。

確かにこれを達成するためのより簡単な方法が必要ですか?

(これは実際には入力を使用していないため、ngModelChangesは使用できません)。

import {Component, Input, Output, EventEmitter, OnInit, OnChanges} from 'angular2/core'; 

@Component({ 
    selector: 'form-select', 
    templateUrl: './app/assets/scripts/modules/form-controls/form-select/form-select.component.html', 
    styleUrls: ['./app/assets/scripts/modules/form-controls/form-select/form-select.component.css'], 
    inputs: [ 
    'options', 
    'callback', 
    'model', 
    'label' 
    ] 
}) 

export class FormSelectComponent implements OnInit, OnChanges { 
    @Input() model: any; 
    @Output() modelChange: EventEmitter = new EventEmitter(); 

    public isOpen: boolean = false; 

    ngOnInit() { 

    if (!this.model) { 
     this.model = {}; 
    } 

    for (var option of this.options) { 

     if (option.model == (this.model.model || this.model)) { 
     this.model = option; 

     } 
    } 
    } 

    ngOnChanges(changes: {[model: any]: SimpleChange}) { 
    console.log(changes); 
    this.modelChange.next(changes['model'].currentValue); 
    } 

    toggle() { 
    this.isOpen = !this.isOpen; 
    } 

    close() { 
    this.isOpen = false; 
    } 

    select(option, callback) { 
    this.model = option; 
    this.close(); 

    callback ? callback() : false; 
    } 

    isSelected(option) { 
    return option.model === this.model.model; 
    } 
} 

編集:私は(上記の更新されたコードを参照)ngOnChangesを使用してみましたが、それは唯一の初期化時に一度実行されます、それは変更を検出しません。何か間違っていますか?あなたはmodelゲッター/セッターを作るか@Input()値が変更された後たびに呼び出されngOnChanges(changes) {}メソッドを追加することにより、OnChangesを実装することができますいずれか

答えて

18

だから私の質問は、入力されたプロパティの値がmodel変更された場合、私は見ることができる場所を$見ます。

modelではJavaScriptプリミティブ型(数値、文字列、論理値)である場合は、NOTIFするngOnChanges()を実装することができます変更のied。 cookbook exampleおよびlifecycle doc, OnChanges sectionを参照してください。
もう1つのオプションは、セッターとゲッターを使用することです。 cookbook exampleを参照してください。

modelは、JavaScriptの参照型(配列、オブジェクト、日付など)であれば、あなたが変更を検出する方法をどのようにモデルの変更に依存します。

  • モデル参照が変更された場合(つまり、あなたが割り当て新しい配列、新しいオブジェクトなど)、プリミティブ型の場合と同様に、ngOnChanges()を実装して変更を通知できます。
  • しかし、モデル参照が変更されずにモデルの一部のプロパティが変更された場合(たとえば、配列項目の値が変更されたり、配列項目が追加または削除されたり、オブジェクトのプロパティ値が変更された場合ngDoCheck()を実装して、独自の変更検出ロジックを実装することができます。
    lifecycle doc, DoCheck sectionを参照してください。
+0

Set/getはうまくいきません。エラーが多発します。ngOnChangesはコンポーネント内の値を変更してから2つの方法で親コンポーネントにバインドするため動作しません。 ngDoCheck()は、変更されたかどうかを知る必要があるだけであり、内部に特定のロジックは必要ありません。私が本当に好きなのはオブザーバーを使うことですが、私はそれを実装する方法を忘れています。オブザーバーでこれを達成する方法を教えてください。私のコードを使用して、私のユースケースとは全く異なるいくつかのランダムな例ではありません。私は怒っているように感謝します。 – Chrillewoodz

+0

ngDoCheck()に関して、Angularは私たちのReferenceTypesの構造を魔法のように知ることができないので、独自の変更検出ロジックを記述する必要がある場合は余計ではありません。 (これは、私が参照しているライフサイクルのドキュメントで議論されています。) 'model'は入力プロパティなので、observableではなくngDoCheck()を使います。あなたは、単に動作していない作品を示す単純なプランカーを持っていますか? –

+0

"モデルは入力プロパティなので、オブザーバブルの代わりにngDoCheck()を使用します。"どうしてこれなの? http要求以外にobservablesを正確に使うべきでしょうか?以前のモデルと照合してdoCheckを使って作業したり、無限ループになったりしました。 – Chrillewoodz

0

ドキュメントからngOnChanges()例(上記のリンク):

@Component({ 
    selector: 'my-cmp', 
    template: `<p>myProp = {{myProp}}</p>` 
}) 
class MyComponent implements OnChanges { 
    @Input() myProp: any; 
    ngOnChanges(changes: {[propName: string]: SimpleChange}) { 
    console.log('ngOnChanges - myProp = ' + changes['myProp'].currentValue); 
    } 
} 
@Component({ 
    selector: 'app', 
    template: ` 
    <button (click)="value = value + 1">Change MyComponent</button> 
    <my-cmp [my-prop]="value"></my-cmp>`, 
    directives: [MyComponent] 
}) 
export class App { 
    value = 0; 
} 
bootstrap(App).catch(err => console.error(err)); 

更新

model変化の内部状態なくmodel自体(異なるmodelインスタンス)を検出を変更した場合それを認識しません。関心のあるコードに通知するために、のObservableを使用して、コンポーネントの購読可能な変更イベントを発行するような独自のメカニズムを実装する必要があります。 someFieldInParent<my-comp [model]="someFieldInParent">に変更されていると角がMyComponentmodelに新しい値を通過したときmodelは、データバインディング(変化したとき

またngOnChanges()だけ呼ばれる。

return option.model === this.model.model;ngOnChanges()が呼び出されることはありません。についてこれはゲッター/セッターのアプローチは、より良いフィット感で動作するカスタム・コンポーネントを選択した場合

+0

[OK]を、私はngOnChangesを見て、しかし、あなたはあなたの答えが受け入れを取得したい場合にも、いくつかのサンプルコードが含まれてくださいます;) – Chrillewoodz

+0

が完了、。 。 。 。 。 。 –

+0

更新された質問を確認してください、最初に行った後に何かを検出するように見えることはできません。 – Chrillewoodz

2

が内部フォーム入力(複数可)を使用して、私はそれ/それらにngModelChangeイベントを活用します:。

<select [ngModel]="..." (ngModelUpdate)="triggerUpdate($event)">…</select> 

または対応するコントロールがあればそれが観測可能なvalueChanges。テンプレートで:

コンポーネントで
<select [ngFormControl]="myForm.controls.selectCtrl">…</select> 

:$スコープのようなものがあるかどう

myForm.controls.selectCtrl.valueChanges.subscribe(newValue => { 
    (...) 
}); 
+0

Mmh、これは実際のフォーム要素ではどうしたらいいのですか?しかし、ul/li要素を使用するカスタムセレクトではうまくいかないので、観測可能な解決方法があります。私は彼らがどのように働くのか理解できました、笑。 – Chrillewoodz

+0

ちょっと考えてみてください:コンポーネントの選択したものでemitメソッドを呼び出すのはなぜですか? ;-) –

+0

モデルが変わる唯一の場所ではないので、3つの異なる方法を変えることができます。これは最初のやり方ですが、既存の値を最初に受け取ったときにモデルを更新しなければならないこと、また値がなく、モデルを空のオブジェクトに設定する必要があることを認識しました。 – Chrillewoodz

1

ngAfterViewCheckedは、DOMがレンダリングされた後に呼び出され、ここで任意の操作を行うことができるので、より良いライフサイクルメソッドです。

https://stackoverflow.com/a/35493028/6522875