简体   繁体   English

AngularJS $watch 的 Angular 等价物是什么?

[英]What is the Angular equivalent to an AngularJS $watch?

In AngularJS you were able to specify watchers to observe changes in scope variables using the $watch function of the $scope .在 AngularJS 中,您可以使用 $ $scope$watch函数指定观察者来观察作用域变量的变化。 What is the equivalent of watching for variable changes (in, for example, component variables) in Angular?在 Angular 中监视变量变化(例如,在组件变量中)有什么等价物?

In Angular 2, change detection is automatic... $scope.$watch() and $scope.$digest() RIP在 Angular 2 中,变化检测是自动的... $scope.$watch()$scope.$digest() RIP

Unfortunately, the Change Detection section of the dev guide is not written yet (there is a placeholder near the bottom of the Architecture Overview page, in section "The Other Stuff").不幸的是,开发指南的变更检测部分尚未编写(在“架构概述”页面底部附近的“其他内容”部分中有一个占位符)。

Here's my understanding of how change detection works:这是我对变化检测如何工作的理解:

  • Zone.js "monkey patches the world" -- it intercepts all of the asynchronous APIs in the browser (when Angular runs). Zone.js “monkey patches the world”——它拦截浏览器中的所有异步 API(当 Angular 运行时)。 This is why we can use setTimeout() inside our components rather than something like $timeout ... because setTimeout() is monkey patched.这就是为什么我们可以在我们的组件中使用setTimeout()而不是$timeout之类的东西......因为setTimeout()是猴子补丁。
  • Angular builds and maintains a tree of "change detectors". Angular 构建并维护一个“变化检测器”树。 There is one such change detector (class) per component/directive.每个组件/指令都有一个这样的变化检测器(类)。 (You can get access to this object by injecting ChangeDetectorRef .) These change detectors are created when Angular creates components. (你可以通过注入ChangeDetectorRef来访问这个对象。)这些变化检测器是在 Angular 创建组件时创建的。 They keep track of the state of all of your bindings, for dirty checking.他们跟踪所有绑定的状态,以进行脏检查。 These are, in a sense, similar to the automatic $watches() that Angular 1 would set up for {{}} template bindings.从某种意义上说,这些类似于 Angular 1 为{{}}模板绑定设置的自动$watches()
    Unlike Angular 1, the change detection graph is a directed tree and cannot have cycles (this makes Angular 2 much more performant, as we'll see below).与 Angular 1 不同,变化检测图是一棵有向树并且不能有循环(这使得 Angular 2 的性能更高,我们将在下面看到)。
  • When an event fires (inside the Angular zone), the code we wrote (the event handler callback) runs.当事件触发时(在 Angular 区域内),我们编写的代码(事件处理程序回调)运行。 It can update whatever data it wants to -- the shared application model/state and/or the component's view state.它可以更新它想要的任何数据——共享应用程序模型/状态和/或组件的视图状态。
  • After that, because of the hooks Zone.js added, it then runs Angular's change detection algorithm.之后,由于添加了挂钩 Zone.js,它会运行 Angular 的变更检测算法。 By default (ie, if you are not using the onPush change detection strategy on any of your components), every component in the tree is examined once (TTL=1)... from the top, in depth-first order.默认情况下(即,如果您没有在任何组件上使用onPush更改检测策略),树中的每个组件都会被检查一次 (TTL=1)... 从顶部开始,按深度优先顺序。 (Well, if you're in dev mode, change detection runs twice (TTL=2). See ApplicationRef.tick() for more about this.) It performs dirty checking on all of your bindings, using those change detector objects. (好吧,如果您处于开发模式,更改检测会运行两次 (TTL=2)。请参阅ApplicationRef.tick()了解更多信息。)它使用这些更改检测器对象对您的所有绑定执行脏检查。
    • Lifecycle hooks are called as part of change detection.生命周期挂钩被称为变更检测的一部分。
      If the component data you want to watch is a primitive input property (String, boolean, number), you can implement ngOnChanges() to be notified of changes.如果您要查看的组件数据是原始输入属性(字符串、布尔值、数字),您可以实现ngOnChanges()以收到更改通知。
      If the input property is a reference type (object, array, etc.), but the reference didn't change (eg, you added an item to an existing array), you'll need to implement ngDoCheck() (see this SO answer for more on this).如果输入属性是引用类型(对象、数组等),但引用没有改变(例如,您向现有数组添加了一个项目),则需要实现ngDoCheck() (请参阅此 SO回答更多关于这个)。
      You should only change the component's properties and/or properties of descendant components (because of the single tree walk implementation -- ie, unidirectional data flow).您应该只更改组件的属性和/或后代组件的属性(因为单树遍历实现——即单向数据流)。 Here's a plunker that violates that.这里有一个 plunker违反了这一点。 Stateful pipes can also trip you up here.有状态的管道也可以让你在这里绊倒
  • For any binding changes that are found, the Components are updated, and then the DOM is updated.对于找到的任何绑定更改,将更新组件,然后更新 DOM。 Change detection is now finished.更改检测现已完成。
  • The browser notices the DOM changes and updates the screen.浏览器注意到 DOM 更改并更新屏幕。

Other references to learn more:其他参考以了解更多信息:

This behaviour is now part of the component lifecycle.此行为现在是组件生命周期的一部分。

A component can implement the ngOnChanges method in the OnChanges interface to get access to input changes.组件可以在OnChanges接口中实现 ngOnChanges 方法来访问输入更改。

Example:例子:

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

If, in addition to automatic two-way binding, you want to call a function when a value changes, you can break the two-way binding shortcut syntax to the more verbose version.如果除了自动双向绑定之外,您还想在值更改时调用函数,则可以将双向绑定快捷语法改为更冗长的版本。

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

is shorthand for是简写

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

(see eg http://victorsavkin.com/post/119943127151/angular-2-template-syntax ) (参见例如http://victorsavkin.com/post/119943127151/angular-2-template-syntax

You could do something like this:你可以这样做:

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

You can use getter function or get accessor to act as watch on angular 2.您可以使用getter functionget accessor充当角度 2 上的手表。

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

Here is another approach using getter and setter functions for the model.这是为模型使用 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;
  }
}

If you want to make it 2 way binding, you can use [(yourVar)] , but you have to implement yourVarChange event and call it everytime your variable change.如果你想让它成为双向绑定,你可以使用[(yourVar)] ,但你必须实现yourVarChange事件并在每次变量更改时调用它。

Something like this to track the hero change像这样跟踪英雄变化

@Output() heroChange = new EventEmitter();

and then when your hero get changed, call this.heroChange.emit(this.hero);然后当你的英雄改变时,调用this.heroChange.emit(this.hero);

the [(hero)] binding will do the rest for you [(hero)]绑定将为您完成剩下的工作

see example here:看这里的例子:

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

This does not answer the question directly, but I have on different occasions landed on this Stack Overflow question in order to solve something I would use $watch for in angularJs.这并没有直接回答这个问题,但是我在不同的场合遇到了这个 Stack Overflow 问题,以解决我会在 angularJs 中使用 $watch 的问题。 I ended up using another approach than described in the current answers, and want to share it in case someone finds it useful.我最终使用了当前答案中描述的另一种方法,并希望分享它以防有人发现它有用。

The technique I use to achieve something similar $watch is to use a BehaviorSubject ( more on the topic here ) in an Angular service, and let my components subscribe to it in order to get (watch) the changes.我用来实现类似$watch的技术是在 Angular 服务中使用BehaviorSubject更多关于主题),并让我的组件订阅它以获取(观察)更改。 This is similar to a $watch in angularJs, but require some more setup and understanding.这类似于 angularJs 中的$watch ,但需要更多设置和理解。

In my component:在我的组件中:

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

In my service在我的服务中

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

Here is a demo on Stackblitz这是Stackblitz上的演示

In AngularJS you were able to specify watchers to observe changes in scope variables using the $watch function of the $scope .在AngularJS你能够指定观察者,观察使用范围变量的变化$watch的功能$scope What is the equivalent of watching for variable changes (in, for example, component variables) in Angular?在 Angular 中观察变量变化(例如,组件变量)的等价物是什么?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM