AngularJS $ watchに相当するAngularは何ですか?


213

AngularJSでは、の$watch関数を使用してスコープ変数の変更を監視するウォッチャーを指定することができました$scope。Angularで変数の変化(コンポーネント変数など)を監視することに相当することは何ですか?


typescriptでgetアクセサーを使用します。
jmvtrinidad 2016

回答:


268

Angular 2では、変更検出は自動的に行われます... $scope.$watch()そして$scope.$digest()RIP

残念ながら、開発ガイドの「変更の検出」セクションはまだ書かれていません(「アーキテクチャの概要」ページの下部、「その他のこと」セクションのプレースホルダーがあります)。

変更検出の仕組みについての私の理解は次のとおりです。

  • Zone.jsは「サルが世界にパッチを当てます」-(Angularの実行時に)ブラウザーのすべての非同期APIをインターセプトします。これが...のsetTimeout()ようなものではなく、コンポーネントの内部で使用できる理由です。猿がパッチされている$timeoutからsetTimeout()です。
  • Angularは「変化検出器」のツリーを構築して維持します。コンポーネント/ディレクティブごとに、このような変更検出器(クラス)が1つあります。(を注入することにより、このオブジェクトにアクセスできますChangeDetectorRef。)これらの変更検出器は、Angularがコンポーネントを作成するときに作成されます。ダーティチェックのために、すべてのバインディングの状態を追跡します。これらは、ある意味では、$watches()Angular 1が{{}}テンプレートバインディング用にセットアップする自動に似ています。
    Angular 1と​​は異なり、変更検出グラフは有向ツリーであり、循環を持つことはできません(これにより、Angular 2のパフォーマンスが大幅に向上します(以下を参照)。
  • イベントが発生すると(Angularゾーン内)、作成したコード(イベントハンドラーコールバック)が実行されます。共有アプリケーションモデル/状態やコンポーネントのビュー状態など、必要なデータを更新できます。
  • その後、追加されたフックZone.jsにより、Angularの変更検出アルゴリズムが実行されます。デフォルトでは(つまり、onPushコンポーネントのいずれかで変更検出戦略を使用していない場合)、ツリー内のすべてのコンポーネントが1回検査されます(TTL = 1)...深さ優先で上から。(まあ、開発モードの場合、変更検出は2回(TTL = 2)実行されます。これについて詳しくは、ApplicationRef.tick()を参照してください。)これらの変更検出オブジェクトを使用して、すべてのバインディングでダーティチェックを実行します。
    • ライフサイクルフックは、変更検出の一部として呼び出されます。
      監視するコンポーネントデータがプリミティブ入力プロパティ(String、boolean、number)である場合ngOnChanges()、変更を通知するように実装できます。
      入力プロパティが参照タイプ(オブジェクト、配列など)であるが、参照が変更されなかった場合(たとえば、既存の配列に項目を追加した場合)、実装する必要がありますngDoCheck()(詳細については、このSOの回答を参照してください)これについて)。
      コンポーネントのプロパティおよび/または子孫コンポーネントのプロパティのみを変更する必要があります(単一ツリーウォークの実装、つまり単方向データフローのため)。ここだplunkerそれに違反します。ステートフルパイプもできるあなたをつまずかせるここに。
  • 見つかったバインディングの変更については、コンポーネントが更新され、次にDOMが更新されます。これで変更検出が終了しました。
  • ブラウザはDOMの変更を認識し、画面を更新します。

詳細については、その他の参考資料:


window.addEventListener()は、変数が変更されたときに検出をトリガーしません...それは私を狂わせ、どこにも何もありません。
アルバートジェームズテディ

@AlbertJamesTeddyは、参照hostで、「ホスト・リスナー」のドキュメントDirectiveMetadataのAPIドキュメントを。Angularゾーン内からグローバルイベントをリッスンする方法を説明します(したがって、変更検出は必要に応じてトリガーされます)。 この回答には効果的なプランカーがあります。
Mark Rajcok 2016年

この リンクは役に立ちます..
リファクタリング

@MarkRajcok、私は変更検出に関する私の記事への参照を自由に追加しました。よろしくお願いします。フードの下で何が起こるかを非常に詳細に説明します。
Max Koretskyi 2017

単方向データフロールールに違反するplunkrに関して、enableProdMode()でplunkrを実行すると、変更検出器が1回しか実行されないため、親ビューに更新が表示されないことを追加します。
Mister_L 2017年

93

この動作は現在、コンポーネントのライフサイクルの一部です。

コンポーネントはOnChangesインターフェイスにngOnChangesメソッドを実装して、入力の変更にアクセスできます。

例:

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


@Component({
  selector: 'hero-comp',
  templateUrl: 'app/components/hero-comp/hero-comp.html',
  styleUrls: ['app/components/hero-comp/hero-comp.css'],
  providers: [],
  directives: [],

  pipes: [],
  inputs:['hero', 'real']
})
export class HeroComp implements OnChanges{
  @Input() hero:Hero;
  @Input() real:string;
  constructor() {
  }
  ngOnChanges(changes) {
      console.log(changes);
  }
}

77
これは@Input()にのみ当てはまります。コンポーネント自体のデータの変更を追跡する場合、これは機能しません
LanderV '26 / 02/26

4
単純な変数(ブール値など)の変更を取得できませんでした。オブジェクトの変更のみが検出されます。
mtoloo 2016年

コンポーネントのデコレータに「入力」配列を追加する必要があるのはなぜですか?変更検出はこれなしでも機能します。
Gil Epshtain

68

自動双方向バインディングに加えて、値が変更されたときに関数を呼び出したい場合は、双方向バインディングショートカット構文をより詳細なバージョンに分割できます。

<input [(ngModel)]="yourVar"></input>

の略記です

<input [ngModel]="yourVar" (ngModelChange)="yourVar=$event"></input>

(例:http : //victorsavkin.com/post/119943127151/angular-2-template-syntaxを参照)

あなたはこのようなことをすることができます:

<input [(ngModel)]="yourVar" (ngModelChange)="changedExtraHandler($event)"></input>


最後の例では、ngModelの周りの[]を削除するつもりでしたか?
Eugene Kulabuhov

16

getter functionまたはget accessorを使用して、角度2のウォッチとして機能できます。

こちらのデモをご覧ください

import {Component} from 'angular2/core';

@Component({
  // Declare the tag name in index.html to where the component attaches
  selector: 'hello-world',

  // Location of the template for this component
  template: `
  <button (click)="OnPushArray1()">Push 1</button>
  <div>
    I'm array 1 {{ array1 | json }}
  </div>
  <button (click)="OnPushArray2()">Push 2</button>
  <div>
    I'm array 2 {{ array2 | json }}
  </div>
  I'm concatenated {{ concatenatedArray | json }}
  <div>
    I'm length of two arrays {{ arrayLength | json }}
  </div>`
})
export class HelloWorld {
    array1: any[] = [];
    array2: any[] = [];

    get concatenatedArray(): any[] {
      return this.array1.concat(this.array2);
    }

    get arrayLength(): number {
      return this.concatenatedArray.length;
    }

    OnPushArray1() {
        this.array1.push(this.array1.length);
    }

    OnPushArray2() {
        this.array2.push(this.array2.length);
    }
}

12

モデルにゲッター関数とセッター関数を使用する別のアプローチを次に示します。

@Component({
  selector: 'input-language',
  template: `
  …
  <input 
    type="text" 
    placeholder="Language" 
    [(ngModel)]="query" 
  />
  `,
})
export class InputLanguageComponent {

  set query(value) {
    this._query = value;
    console.log('query set to :', value)
  }

  get query() {
    return this._query;
  }
}

4
この件は正気ではありません。複雑なフォームに関連付けられた多くのプロパティを持つオブジェクトがあります。(change)それらすべてにハンドラを追加したくありません。get|setsモデルのすべてのプロパティにs を追加したくありません。get|setfor を追加しても役に立ちませんthis.objects ngOnChanges() @Inputの変更のみを検出します。聖なるマナ!彼らは私たちに何をしましたか?ある種のディープウォッチを返してください!
コーディ

6

双方向バインディングにしたい場合はを使用でき[(yourVar)]ますがyourVarChange、変数を変更するたびにイベントを実装して呼び出す必要があります。

ヒーローの変化を追跡するためのこのようなもの

@Output() heroChange = new EventEmitter();

そしてあなたのヒーローが変わったら、電話して this.heroChange.emit(this.hero);

[(hero)]あなたのための残りを行いますバインディング

ここの例を参照してください:

http://plnkr.co/edit/efOGIJ0POh1XQeRZctSx?p=preview



2

これは質問に直接答えることはしませんが、角度スタックで$ watchを使用することを解決するために、このスタックオーバーフローの質問にさまざまな場面で遭遇しました。私は現在の回答で説明されているものとは別のアプローチを使用することになりました。

私が同様のことを達成するために使用する手法は、Angularサービスで(詳細についてはこちらのトピックを参照$watchを使用し、変更を取得(監視)するためにコンポーネントにサブスクライブさせることです。これはangularJsのa に似ていますが、さらに設定と理解が必要です。BehaviorSubject$watch

私のコンポーネントでは:

export class HelloComponent {
  name: string;
  // inject our service, which holds the object we want to watch.
  constructor(private helloService: HelloService){
    // Here I am "watching" for changes by subscribing
    this.helloService.getGreeting().subscribe( greeting => {
      this.name = greeting.value;
    });
  }
}

私のサービスで

export class HelloService {
  private helloSubject = new BehaviorSubject<{value: string}>({value: 'hello'});
  constructor(){}
  // similar to using $watch, in order to get updates of our object 
  getGreeting(): Observable<{value:string}> {
    return this.helloSubject;
  }
  // Each time this method is called, each subscriber will receive the updated greeting.
  setGreeting(greeting: string) {
    this.helloSubject.next({value: greeting});
  }
}

Stackblitzのデモです

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.