Reputation: 12351
This may be my own misunderstanding of how Angular 2 change detection works but I would have expected that if a component's ChangeDetectionStrategy
was set to Checked
, CheckOnce
or Detached
, that that component would only check for changes once when the component is instantiated. It appears to not happen that way.
import {Component, OnInit, ChangeDetectionStrategy} from 'angular2/core'
@Component({
selector: 'my-app',
providers: [],
template: `
<div>
<button
(click)="onClick($event)"
[class.thing]="hasThingClass()">Update</button>
</div>
`,
changeDetection:ChangeDetectionStrategy.CheckOnce,
styles: [`
.thing { background-color: red }
`]
})
export class App implements OnInit {
public hasThing:Boolean = false;
onClick() {
this.hasThing = !this.hasThing;
}
hasThingClass(e) {
return this.hasThing;
}
}
On click I would have expected to toggle the hasThing
property but I wouldn't have expected the view to update. As it happens, the view does update. The occurs when the ChangeDetectionStrategy
is set to Detached
also.
http://plnkr.co/edit/2hHdt2BDpj419Z32iPjJ?p=preview
What am I missing here? What exactly is causing the view to update? From what I can see, regardless of me updating the hasThing
property, the view updates on click whether a value has changed or not.
Upvotes: 1
Views: 7756
Reputation: 364677
Regardless of the ChangeDetectionStrategy setting, Angular will check the component for changes whenever
The idea being... if the component triggered an event, or a bound observable value changed, most likely you want to update its view.
Upvotes: 8
Reputation: 1506
I hope this will help you understand it :)
http://plnkr.co/edit/sM8CCSl8hXyRVAaTZH4N?p=preview
Let's say we have an async event which i simulate in my service:
import { Injectable } from 'angular2/core';
@Injectable()
export class DataProvider {
data = 1;
constructor() {
// async data change simulation
setInterval(() => {
this.data = this.data * 2;
}, 500);
}
}
When angular spot any async event change via zones api , zone notify an angular in that context an async event happened and it propagate it to angular change detection api to do check between actual view and component, and in example below we can see that since change detection behaviour is not changed angular is constantly updating view:
import {
Component
} from 'angular2/core';
import { bootstrap } from 'angular2/platform/browser';
import { DataProvider } from './data-provider';
import { TriggerDataChange } from './data-change-trigger';
@Component({
selector: 'app',
template: `
<div>Live Update: {{dataProvider.data}} </div>
<data-change-trigger></data-change-trigger>
`,
providers: [DataProvider],
directives: [TriggerDataChange]
})
class App {
constructor(private dataProvider:DataProvider) {}
}
bootstrap(App);
Scenario two with changed behaviour of change detection, since ChangeDetectionStrategy is set to CheckOnce angular will trigger change detection only once at component initialization process and in that case you have to trigger change manually to update view which in this case is done by event binding:
import {
Component,
ChangeDetectionStrategy,
ChangeDetectorRef
} from 'angular2/core';
import { DataProvider } from './data-provider';
@Component({
selector: 'data-change-trigger',
changeDetection: ChangeDetectionStrategy.CheckOnce,
template: `
Trigger update:
<button (click)="update($event)">Update</button>
<div>{{dataProvider.data}}</div>
`
})
export class TriggerDataChange {
constructor(
private ref: ChangeDetectorRef,
private dataProvider:DataProvider
) {}
update($event) {
console.log('event', $event);
}
}
And finally to answer why is in your case view is updated ? It's because event binding in template:
(click)="onClick($event)"
This is an native event which is triggering current component ChangeDetectorRef.detectChanges()
Upvotes: 4