Angular 等同于 AngularJS $watch 是什么?

What is the Angular equivalent to an AngularJS $watch?

在 AngularJS 中,您可以使用 $scope$watch 函数指定观察者来观察作用域变量的变化。在 Angular 中观察变量变化(例如,在组件变量中)的等价物是什么?

此行为现在是组件生命周期的一部分。

组件可以在 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);
  }
}

在 Angular 2 中,更改检测是自动的... $scope.$watch()$scope.$digest() R.I.P.

不幸的是,开发指南的更改检测部分尚未编写(在 Architecture Overview 页面底部附近的 "The Other Stuff" 部分中有一个占位符)。

以下是我对变化检测工作原理的理解:

  • Zone.js "monkey patches the world" -- 它拦截浏览器中的所有异步 API(当 Angular 运行时)。这就是为什么我们可以在我们的组件中使用 setTimeout() 而不是像 $timeout... 因为 setTimeout() 是猴子补丁。
  • Angular 构建并维护 "change detectors" 的树。每个 component/directive 有一个这样的变化检测器 (class)。 (您可以通过注入 ChangeDetectorRef 来访问此对象。)这些更改检测器是在 Angular 创建组件时创建的。他们跟踪所有绑定的状态,以进行脏检查。从某种意义上说,这些类似于 Angular 1 为 {{}} 模板绑定设置​​的自动 $watches()
    与 Angular 1 不同,更改检测图是一棵有向树,不能有循环(这使得 Angular 2 的性能更高,我们将在下面看到)。
  • 当事件触发时(在 Angular 区域内),我们编写的代码(事件处理程序回调)运行。它可以更新它想要的任何数据——共享应用程序 model/state and/or 组件的视图状态。
  • 之后,由于添加了挂钩 Zone.js,它会运行 Angular 的更改检测算法。默认情况下(即,如果您没有在任何组件上使用 onPush 更改检测策略),树中的每个组件都会被检查一次 (TTL=1)...从顶部开始,在 depth-first 命令。 (好吧,如果您处于开发模式,更改检测会运行两次 (TTL=2)。有关更多信息,请参阅 ApplicationRef.tick()。)它使用这些更改检测器对象对您的所有绑定执行脏检查。
    • 生命周期挂钩被称为变更检测的一部分。
      如果您要查看的组件数据是原始输入 属性(字符串、布尔值、数字),您可以实现 ngOnChanges() 以获得更改通知。
      如果输入 属性 是引用类型(对象、数组等),但引用没有改变(例如,您向现有数组添加了一个项目),您将需要实施 ngDoCheck()(请参阅此处 for more on this).
      You should only change the component's properties and/or properties of descendant components (because of the single tree walk implementation -- i.e., unidirectional data flow). Here's a plunker that violates that. Stateful pipes can also
  • 对于找到的任何绑定更改,更新组件,然后更新 DOM。更改检测现已完成。
  • 浏览器注意到 DOM 更改并更新屏幕。

其他参考以了解更多信息:

如果除了自动 two-way 绑定之外,您还想在值更改时调用函数,则可以将 two-way 绑定快捷语法改为更冗长的版本。

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

对于

来说是shorthand

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

(参见 http://victorsavkin.com/post/119943127151/angular-2-template-syntax

你可以这样做:

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

如果你想让它成为双向绑定,你可以使用 [(yourVar)],但你必须实现 yourVarChange 事件并在每次变量更改时调用它。

像这样跟踪英雄变化

@Output() heroChange = new EventEmitter();

然后当你的英雄改变时,调用this.heroChange.emit(this.hero);

[(hero)] 绑定将为您完成剩下的工作

在此处查看示例:

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

您可以使用 getter functionget accessor 来监视 angular 2.

查看演示 here

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

这是使用模型的 getter 和 setter 函数的另一种方法。

@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;
  }
}

当您的应用程序仍然 需要$parse$eval$watch 类似Angular[=14 中的行为时尝试此操作=]

https://github.com/vinayk406/angular-expression-parser

这并没有直接回答问题,但我在不同的场合下遇到过这个 Stack Overflow 问题,以解决我会在 angularJs 中使用 $watch 的问题。我最终使用了当前答案中描述的另一种方法,并希望分享它以防有人发现它有用。

我用来实现类似 $watch 的技术是在 Angular 服务中使用 BehaviorSubject (more on the topic here),并让我的组件订阅它为了获得(观察)变化。这类似于 angularJs 中的 $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

上的演示