In AngularJS you were able to specify watchers to observe changes in scope variables using the $watch
function of the $scope
. What is the equivalent of watching for variable changes (in, for example, component variables) in Angular?
-
Use get accessor in typescript. – jmvtrinidad Jul 29 '16 at 11:19
-
[check this article](https://hackernoon.com/angulars-digest-is-reborn-in-the-newer-version-of-angular-718a961ebd3e) that explains the difference – Max Koretskyi May 16 '17 at 10:43
7 Answers
In Angular 2, change detection is automatic... $scope.$watch()
and $scope.$digest()
R.I.P.
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). This is why we can use
setTimeout()
inside our components rather than something like$timeout
... becausesetTimeout()
is monkey patched. - Angular builds and maintains a tree of "change detectors". 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. 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.
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). - When an event fires (inside the Angular zone), the code we wrote (the event handler callback) runs. 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. By default (i.e., 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. (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.- 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 implementngOnChanges()
to be notified of changes.
If the input property is a reference type (object, array, etc.), but the reference didn't change (e.g., you added an item to an existing array), you'll need to implementngDoCheck()
(see this SO answer for more on this).
You should only change the component's properties and/or properties of descendant components (because of the single tree walk implementation -- i.e., unidirectional data flow). Here's a plunker that violates that. Stateful pipes can also trip you up here.
- Lifecycle hooks are called as part of change detection.
- For any binding changes that are found, the Components are updated, and then the DOM is updated. Change detection is now finished.
- The browser notices the DOM changes and updates the screen.
Other references to learn more:
- Angular’s $digest is reborn in the newer version of Angular - explains how the ideas from AngularJS are mapped to Angular
- Everything you need to know about change detection in Angular - explains in great detail how change detection works under the hood
- Change Detection Explained - Thoughtram blog Feb 22, 2016 - probably the best reference out there
- Savkin's Change Detection Reinvented video - definitely watch this one
- How does Angular 2 Change Detection Really Work?- jhade's blog Feb 24, 2016
- Brian's video and Miško's video about Zone.js. Brian's is about Zone.js. Miško's is about how Angular 2 uses Zone.js to implement change detection. He also talks about change detection in general, and a little bit about
onPush
. - Victor Savkins blog posts: Change Detection in Angular 2, Two phases of Angular 2 applications, Angular, Immutability and Encapsulation. He covers a lot of ground quickly, but he can be terse at times, and you're left scratching your head, wondering about the missing pieces.
- Ultra Fast Change Detection (Google doc) - very technical, very terse, but it describes/sketches the ChangeDetection classes that get built as part of the tree

- 101,079
- 60
- 333
- 488

- 362,217
- 114
- 495
- 492
-
window.addEventListener() does not trigger detection when variable are changed... it drives me crazy, there's is nothing on that anywhere. – Albert James Teddy Feb 02 '16 at 20:42
-
@AlbertJamesTeddy, see the `host`, "Host Listeners" documentation in the [DirectiveMetadata API doc](https://angular.io/docs/ts/latest/api/core/DirectiveMetadata-class.html#host). It explains how to listen to global events from inside the Angular zone (so change detection will be triggered as desired). [This answer](http://stackoverflow.com/a/36135449/215945) has a working plunker. – Mark Rajcok Mar 22 '16 at 00:32
-
[this](https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html) link would be helpful .. – refactor Aug 08 '16 at 13:04
-
@MarkRajcok, I took a liberty of adding reference to my article on change detection. Hope you don't mind. It explains in great details what happens under the hood. – Max Koretskyi Aug 07 '17 at 18:32
-
Regarding the plunkr that violates the unidirectional data flow rule, I would like to add that if you run the plunkr with enableProdMode(), you will not see any update in the parent view, because the change detector runs only once. – Mister_L Oct 26 '17 at 18:14
-
Since zone.js monkey patches the async functions like `XMLHttpRequest()`, does that mean even external libraries that make HTTP requests will trigger Angular's life cycle? While it sounds like it, you specify "When an event fires (inside the Angular zone)". Plus, based on the zone.js docs, it seems like there can be multiple Zones at any given time. – c1moore Jan 26 '18 at 20:28
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.
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);
}
}

- 30,680
- 7
- 72
- 74
-
85this is only true for @Input(). if you want to track changes of your component's own data, this will not work – LanderV Feb 26 '16 at 15:00
-
4I couldn't get changes of simple variables (boolean for example). Only objects changes are detected. – mtoloo Jun 22 '16 at 07:44
-
why do need to add an "inputs" array in the component's decorator? the change detection will work without this as well. – Gil Epshtain Jan 31 '18 at 10:09
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 e.g. http://victorsavkin.com/post/119943127151/angular-2-template-syntax)
You could do something like this:
<input [(ngModel)]="yourVar" (ngModelChange)="changedExtraHandler($event)"></input>

- 851
- 5
- 5
-
-
To me this is the best answer, especially the last line regarding (ngModelChange). Any time a change is detected in the [(ngModel)], then fire off that function. Brilliant! This is how most of my $watch is being converted into from old AngularJS to new Angular app. – Jason May 09 '21 at 18:27
You can use getter function
or get accessor
to act as watch on angular 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);
}
}

- 14,503
- 5
- 30
- 38

- 3,347
- 3
- 22
- 42
Here is another approach using getter and setter functions for the model.
@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,513
- 2
- 25
- 36
-
8This subject is insane. I have an object with *many* properties tied to a complex form. I don't want to add `(change)` handler(s) on every single one of them; I don't want to add `get|sets`s to every property in my model; it won't help to add a `get|set` for `this.object`; `ngOnChanges()` *only detects changes to `@Input`s*. Holy manna! What did they do to us??? Give us back a deep-watch of some kind! – Cody Feb 01 '17 at 18:13
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.
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);
the [(hero)]
binding will do the rest for you
see example here:

- 1,261
- 2
- 13
- 24
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. 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. This is similar to a $watch
in angularJs, but require some more setup and understanding.
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

- 10,165
- 5
- 55
- 71