Что такое угловой эквивалент AngularJS $watch?


в AngularJS вы смогли указать наблюдателей для наблюдения за изменениями переменных области с помощью на $scope. Каков эквивалент наблюдения за переменными изменениями (например, в компонентных переменных) в Angular?

7 184

7 ответов:

в угловом 2, обнаружение изменения автоматическое... $scope.$watch() и $scope.$digest() Р. И. П.

к сожалению, раздел обнаружения изменений руководства dev еще не написан (есть заполнитель в нижней части Обзор Архитектуры страница, в разделе "остальное").

вот мое понимание того, как работает обнаружение изменений:

  • зоны.js "monkey patches the world" -- он перехватывает все асинхронные API в браузер (когда угловой работает). Вот почему мы можем использовать setTimeout() внутри нашего компонентов, а не что-то вроде $timeout... потому что setTimeout() это патченные.
  • Angular строит и поддерживает дерево "детекторов изменений". Существует один такой детектор изменений (класс) на компонент/директиву. (Вы можете получить доступ к этому объекту, введя ChangeDetectorRef.) Эти детекторы изменения создаются, когда угловой создает компоненты. Они отслеживают состояние всех ваши привязки, для грязной проверки. Это, в некотором смысле, похожи на автоматические $watches() что угловой 1 будет настроен на {{}} привязки шаблона.
    в отличие от углового 1, граф обнаружения изменений является ориентированным деревом и не может иметь циклов (это делает угловой 2 гораздо более производительным, как мы увидим ниже).
  • когда событие срабатывает (внутри угловой зоны), выполняется код, который мы написали (обратный вызов обработчика событий). Он может обновлять любые данные, которые он хочет -- общее приложение модель / состояние и / или состояние представления компонента.
  • после этого, из-за пояса крючки.JS добавил, затем он запускает алгоритм обнаружения изменений Angular. По умолчанию (т. е. если вы не используете onPush изменить стратегию обнаружения на любом из ваших компонентов), каждый компонент в дереве рассматривается один раз (TTL=1)... сверху, в глубину-первый порядок. (Ну, если вы находитесь в режиме dev, обнаружение изменений выполняется дважды (TTL=2). Смотрите ApplicationRef.ТИК() подробнее об этом.) Он выполняет грязную проверку всех ваших Привязок, используя эти объекты детектора изменений.
    • крючки жизненного цикла вызываются как часть обнаружения изменений.
      если данные компонента, которые вы хотите просмотреть, являются примитивным свойством ввода (String, boolean, number), вы можете реализовать ngOnChanges() для уведомления об изменениях.
      если входное свойство является ссылочным типом (объект, массив и т. д.), но ссылка не изменилась (например, вы добавили элемент в существующий массив), вам нужно будет реализовать ngDoCheck() (см. это так ответ подробнее об этом).
      вы должны изменить только свойства компонента и / или свойства компонентов-потомков (из-за реализации одиночного дерева-т. е. однонаправленного потока данных). Вот это в plunker, что нарушает это. Статусные трубы также могут тебе подножку здесь.
  • для каких-либо обязательных изменений, которые будут найдены, то компоненты будут обновлены, а затем DOM обновляется. Обнаружение изменений теперь завершено.
  • браузер замечает изменения DOM и обновляет экран.

другие ссылки, чтобы узнать больше:

такое поведение теперь является частью жизненного цикла компонента.

компонент может реализовать метод ngOnChanges в OnChanges интерфейс для получения доступа к изменениям ввода.

пример:

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

Если в дополнение к автоматической двусторонней привязке вы хотите вызвать функцию при изменении значения, вы можете разбить синтаксис ярлыка двусторонней привязки на более подробную версию.

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

можно использовать 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);
    }

}

вот еще один подход, использующий функции 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;
  }
}

если вы хотите сделать ее 2 способ привязки, вы можете использовать [(yourVar)], но вы должны реализовать yourVarChange событие и вызвать его каждый раз, когда переменная меняется.

что-то вроде этого, чтобы отслеживать изменение героя

@Output() heroChange = new EventEmitter();

а потом, когда ваш герой переоденется, позвоните this.heroChange.emit(this.hero);

the [(hero)] привязка сделает все остальное за вас

см. пример здесь:

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

попробуйте это, когда ваше приложение еще требования $parse,$eval,$watch как поведение в угловой

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