В AngularJS вы могли указать наблюдателей, чтобы наблюдать изменения в переменных области, используя $watch
функцию $scope
. Что эквивалентно наблюдению за изменениями переменных (например, в компонентных переменных) в Angular?
В AngularJS вы могли указать наблюдателей, чтобы наблюдать изменения в переменных области, используя $watch
функцию $scope
. Что эквивалентно наблюдению за изменениями переменных (например, в компонентных переменных) в Angular?
Ответы:
В Angular 2 обнаружение изменений происходит автоматически ... $scope.$watch()
и $scope.$digest()
RIP
К сожалению, раздел «Обнаружение изменений» в руководстве разработчика еще не написан (в нижней части страницы « Обзор архитектуры» в разделе «Прочие материалы» есть место для заполнения).
Вот мое понимание того, как работает обнаружение изменений:
setTimeout()
внутри наших компонентов, а не что-то вроде $timeout
... потому что setTimeout()
залатана обезьяна.ChangeDetectorRef
.) Эти детекторы изменений создаются, когда Angular создает компоненты. Они отслеживают состояние всех ваших привязок, для грязной проверки. В некотором смысле они аналогичны автоматическим, $watches()
которые Angular 1 будет устанавливать для {{}}
привязок к шаблону. onPush
стратегию обнаружения изменений ни для одного из ваших компонентов), каждый компонент в дереве проверяется один раз (TTL = 1) ... сверху, в порядке глубины. (Хорошо, если вы находитесь в режиме разработки, обнаружение изменений запускается дважды (TTL = 2). Подробнее об этом см. ApplicationRef.tick () .) Он выполняет грязную проверку всех ваших привязок, используя эти объекты детектора изменений.
ngOnChanges()
чтобы получать уведомления об изменениях. ngDoCheck()
(см. Этот SO-ответ для получения дополнительной информации). на этом). Другие ссылки, чтобы узнать больше:
onPush
.host
Документацию «Host Listeners» в документе DirectiveMetadata API . В нем объясняется, как прослушивать глобальные события изнутри угловой зоны (поэтому обнаружение изменений будет срабатывать по желанию). У этого ответа есть рабочий поршень.
Это поведение теперь является частью жизненного цикла компонента.
Компонент может реализовать метод 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);
}
}
Вот еще один подход, использующий функции получения и установки для модели.
@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;
}
}
(change)
обработчики для каждого из них; Я не хочу добавлять get|sets
s к каждому свойству в моей модели; это не поможет добавить get|set
для this.object
; ngOnChanges()
обнаруживает только изменения в @Input
с . Святая манна! Что они с нами сделали ??? Верните нам какие-то глубокие часы!
Если вы хотите сделать его двухсторонним связыванием, вы можете использовать его [(yourVar)]
, но вам нужно реализовать yourVarChange
событие и вызывать его каждый раз, когда меняется ваша переменная.
Как то так, чтобы отслеживать смену героя
@Output() heroChange = new EventEmitter();
а потом, когда ваш герой переоденется, позвоните this.heroChange.emit(this.hero);
[(hero)]
связывании остальное сделает за вас
посмотрите пример здесь:
Попробуйте это , когда ваше приложение все еще требует $parse
, $eval
, $watch
как поведение в угловых
Это не дает прямого ответа на вопрос, но я несколько раз сталкивался с этим вопросом переполнения стека, чтобы решить что-то, для чего я бы использовал $ watch в angularJs. Я использовал другой подход, чем описанный в текущих ответах, и хочу поделиться им на случай, если кто-то сочтет это полезным.
Техника, которую я использую для достижения чего-то похожего, $watch
заключается в использовании BehaviorSubject
( подробнее о теме здесь ) в службе Angular и разрешении моим компонентам подписываться на нее, чтобы получать (наблюдать) изменения. Это похоже на $watch
в angularJs, но требует дополнительной настройки и понимания.
В моем компоненте:
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