什么是Angular相当于AngularJS $手表?

Erw*_*win 204 angular2-changedetection angular

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

Mar*_*cok 263

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

遗憾的是,开发指南的"更改检测"部分尚未编写(" 架构概述"页面底部附近有一个占位符,位于"其他内容"部分).

以下是我对变更检测如何工作的理解:

  • Zone.js"猴子修补世界" - 它拦截浏览器中的所有异步API(当Angular运行时).这就是为什么我们可以setTimeout()在我们的组件内使用而不是像$timeout...因为setTimeout()猴子修补.
  • Angular构建并维护一个"变化探测器"树.每个组件/指令有一个这样的变化检测器(类).(您可以通过注入来访问此对象ChangeDetectorRef.)当Angular创建组件时,会创建这些更改检测器.它们会跟踪所有绑定的状态,以便进行脏检查.从某种意义上说,这些类似于$watches()Angular 1为{{}}模板绑定设置的自动化.
    与Angular 1不同,变化检测图是一个有向树,不能有循环(这使得Angular 2的性能更高,我们将在下面看到).
  • 当事件触发时(在Angular区域内),我们编写的代码(事件处理程序回调)运行.它可以更新它想要的任何数据 - 共享应用程序模型/状态和/或组件的视图状态.
  • 之后,由于添加了钩子Zone.js,它然后运行Angular的变化检测算法.默认情况下(即,如果您未onPush在任何组件上使用更改检测策略),树中的每个组件都会从顶部按深度优先顺序检查一次(TTL = 1).(好吧,如果您处于开发模式,更改检测会运行两次(TTL = 2).有关此内容,请参阅ApplicationRef.tick().)它使用这些更改检测器对象对所有绑定执行脏检查.
    • 生命周期钩子被称为变化检测的一部分.
      如果要监视的组件数据是原始输入属性(String,boolean,number),则可以实现ngOnChanges()更改通知.
      如果输入属性是引用类型(对象,数组等),但引用没有改变(例如,您将项添加到现有数组),则需要实现ngDoCheck()(请参阅此SO答案以获取更多信息)在此).
      您应该只更改组件的后代组件的属性和/或属性(因为单个树步行实现 - 即单向数据流).这是一个违反这一点的掠夺者.有状态的管道也可以在这里绊倒你.
  • 对于找到的任何绑定更改,将更新组件,然后更新DOM.变更检测现已完成.
  • 浏览器会注意到DOM更改并更新屏幕.

其他参考资料了解更多:


tos*_*skv 89

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

组件可以在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);
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 这仅适用于@Input().如果要跟踪组件自身数据的更改,这将不起作用 (67认同)
  • 我无法更改简单变量(例如布尔值).仅检测到对象更改. (4认同)

小智 65

如果除了自动双向绑定之外,您希望在值更改时调用函数,则可以将双向绑定快捷方式语法分解为更详细的版本.

<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>


jmv*_*dad 16

您可以使用getter functionget 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);
    }
}
Run Code Online (Sandbox Code Playgroud)


sel*_*ect 11

这是另一种使用模型的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;
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 这个话题很疯狂.我有一个带有*many*属性的对象绑定到复杂的表单.我不想在每一个上添加`(change)`handler(s); 我不想在模型中的每个属性中添加`get | sets`s; 为`this.object`添加`get | set`是没有用的; `ngOnChanges()`*仅检测对`@ Input`s*的更改.神圣的吗哪!他们对我们做了什么?给我们一个深刻的手表! (4认同)

Moh*_*een 6

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

像这样追踪英雄变化的东西

@Output() heroChange = new EventEmitter();
Run Code Online (Sandbox Code Playgroud)

然后当你的英雄变了,打电话 this.heroChange.emit(this.hero);

[(hero)]结合将完成剩下的你

看这里的例子:

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


Joh*_*ohn 5

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

我用来实现类似目标的技术$watch是在 Angular 服务中使用BehaviorSubject更多关于这里的主题),并让我的组件订阅它以获取(观察)更改。这类似于$watchangularJs 中的 a,但需要更多的设置和理解。

在我的组件中:

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;
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

在我的服务

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});
  }
}
Run Code Online (Sandbox Code Playgroud)

这是Stackblitz上的演示