В AngularJS вы могли указать наблюдателей для наблюдения за изменениями в переменных области, используя функцию $watch
из $scope
. Что эквивалентно наблюдению за изменениями переменных (например, в компонентных переменных) в Angular?
Что такое угловой эквивалент часов AngularJS $?
Ответ 1
В Angular 2 обнаружение изменений происходит автоматически... $scope.$watch()
и $scope.$digest()
R.I.P.
К сожалению, раздел "Обнаружение изменений" в руководстве разработчика еще не написан (есть местозаполнитель в нижней части страницы Обзор архитектуры, в разделе "Другое вещество" ).
Здесь мое понимание того, как работает обнаружение изменений:
- "Обезьяна Zone.js" исправляет мир "- она перехватывает все асинхронные API в браузере (когда Angular работает). Вот почему мы можем использовать
setTimeout()
внутри наших компонентов, а не что-то вроде$timeout
... потому чтоsetTimeout()
- обезьяна исправлена. - Angular строит и поддерживает дерево "детекторов изменений". Существует один такой детектор (класс) изменения для каждого компонента/директивы. (Вы можете получить доступ к этому объекту, введя
ChangeDetectorRef
.) Эти детекторы изменений создаются, когда Angular создает компоненты. Они отслеживают состояние всех ваших привязок, для грязной проверки. Они в некотором смысле похожи на автоматический$watches()
, который Angular 1 будет настроен для привязок шаблонов{{}}
.
В отличие от Angular 1, график обнаружения изменений является направленным деревом и не может иметь циклов (это делает Angular 2 намного более результативным, как мы увидим ниже). - Когда происходит событие (внутри зоны Angular), выполняется код, который мы написали (обратный вызов обработчика события). Он может обновлять любые данные, которые он хочет - общая модель/состояние приложения и/или состояние представления компонентов.
- После этого из-за добавления hooks Zone.js в нем выполняется Angular алгоритм обнаружения изменений. По умолчанию (т.е. Если вы не используете стратегию обнаружения изменений
onPush
для любого из ваших компонентов), каждый компонент в дереве рассматривается один раз (TTL = 1)... сверху, в глубине-первом порядке. (Ну, если вы находитесь в режиме dev, изменение обнаружения выполняется дважды (TTL = 2). Подробнее об этом см. ApplicationRef.tick()..) Он выполняет грязную проверку всех ваших привязок, используя те объекты детекторов изменения.- Перехватчики жизненного цикла называются частью обнаружения изменений.
Если данные компонента, которые вы хотите просмотреть, являются примитивным входным свойством (String, boolean, number), вы можете реализоватьngOnChanges()
для уведомления об изменениях.
Если свойство ввода является ссылочным типом (объект, массив и т.д.), но ссылка не изменилась (например, вы добавили элемент в существующий массив), вам нужно реализоватьngDoCheck()
( см. этот SO ответ для получения дополнительной информации об этом).
Вы должны только изменять свойства компонента и/или свойства компонентов-потомков (из-за реализации единого дерева, т.е. Потока однонаправленных данных). Здесь plunker, который нарушает это. Состоятельные трубки также могут отследить вас здесь.
- Перехватчики жизненного цикла называются частью обнаружения изменений.
- Для любых найденных изменений привязки компоненты обновляются, а затем обновляется DOM. Обнаружение изменений завершено.
- Браузер замечает изменения DOM и обновляет экран.
Другие ссылки, чтобы узнать больше:
- Angular s $digest обновляется в новой версии Angular - объясняет, как идеи от AngularJS отображаются на Angular
- Все, что вам нужно знать об обнаружении изменений в Angular - подробно объясняет, как работает обнаружение изменений под капотом
- Обнаружено изменение обнаружения - Блог Thoughtram 22 февраля 2016 года - возможно, наилучшая ссылка там
- Savkin Изменено обнаружение изменено - обязательно просмотрите этот
- Как Angular 2 Обнаружение изменения действительно работает? - блог jhade 24 февраля 2016 г.
- видео Брайана и видео Miško о Zone.js, Брайан о Zone.js. Мишко рассказывает о том, как Angular 2 использует Zone.js для реализации обнаружения изменений. Он также говорит об обнаружении изменений вообще, и немного о
onPush
. - Сообщения в блоге Victor Savkins: Обнаружение изменений в Angular 2, Две фазы Angular 2 приложений, Angular, неизменность и инкапсуляция. Он быстро покрывает много земли, но временами он может быть кратким, и вы остаетесь царапать голову, задаваясь вопросом о недостающих частях.
- Ультра быстрое обнаружение изменений (документ Google) - очень технический, очень краткий, но он описывает/зарисовывает классы ChangeDetection, которые создаются как часть дерева
Ответ 2
Это поведение теперь является частью жизненного цикла компонента.
Компонент может реализовать метод 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);
}
}
Ответ 3
Если в дополнение к автоматической двусторонней привязке вы хотите вызвать функцию при изменении значения, вы можете разбить синтаксис ярлыка двусторонней привязки на более подробную версию.
<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>
Ответ 4
Вы можете использовать getter function
get accessor
или 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);
}
}
Ответ 5
Вот еще один подход с использованием функций 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;
}
}
Ответ 6
Если вы хотите сделать его привязкой по 2 способам, вы можете использовать [(yourVar)]
, но вы должны реализовать событие yourVarChange
и вызывать его каждый раз, когда изменяется ваша переменная.
Что-то вроде этого, чтобы отслеживать изменение героя
@Output() heroChange = new EventEmitter();
а затем, когда ваш герой будет изменен, вызовите this.heroChange.emit(this.hero);
привязка [(hero)]
сделает все остальное для вас
см. пример здесь:
Ответ 7
Попробуйте, когда ваше приложение еще требует $parse
, $eval
, $watch
как поведение в Angular
Ответ 8
Это не дает прямого ответа на вопрос, но я несколько раз сталкивался с вопросом о переполнении стека, чтобы решить что-то, для чего я бы использовал $ 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