This discussion lists a few strategies https://github.com/angular/angular/issues/6674#issuecomment-174699245
The question has many implications. In some cases, the observables should be managed outside of the framework.
A. You can scan all observables before you bootstrap
B. Bootstrap then scan all observables before passing the object to the top level component.
C. You can also change the changeDetection within the component to either trigger when inputs changes or manually trigger the change detector them.
D. If you're using |async then it should only be used at the top level if you don't feel like using .subscribe but you really should just use .subscribe.
E. If you're using |async everywhere then what you're really doing is inverting control over rendering to the observables which means we're back in the Angular1 days of cascading changes so you either need to do C, D, B, or A
ChangeDetectionStrategy doesn't seem to be working at the moment. You would simple set the component as Detached.
We can also use ngOnInit lifecycle hook to remove the component from the change detection tree. You would need to run this.ref.detach(); where ref is injected via ChangeDetectorRef
ngOnInit() {
this.ref.detach();
}
makeYourChanges() {
this.ref.reattach(); // attach back to change detector tree
this.data.value = Math.random() + ''; // make changes
this.ref.detectChanges(); // check as dirty
this.ref.detach(); // remove from tree
// zone.js triggers changes
}
ChangeDetectorRef
You can also not include zone.js and manually control all changes. You can also inject NgZone to run an operation outside of zone.js so it won't tell angular to trigger chanes. For example,
// this example might need a refactor to work with rxjs 5
export class Timeflies {
pos = 'absolute';
color = 'red';
letters: LetterConfig[];
constructor(
private service: Message,
private el: ElementRef,
private zone: NgZone) {
}
ngOnInit() {
// initial mapping (before mouse moves)
this.letters = this.service.message.map(
(val, idx) => ({
text: val,
top: 100,
left: (idx * 20 + 50),
index: idx
})
);
this.zone.runOutsideAngular(() => {
Observable
.fromEvent(this.el.nativeElement, 'mousemove')
.map((e: MouseEvent) => {
//var offset = getOffset(this.el);
// subtract offset of the element
var o = this.el.nativeElement.getBoundingClientRect();
return {
offsetX: e.clientX - o.left,
offsetY: e.clientY - o.top
};
})
.flatMap(delta => {
return Observable
.fromArray(this.letters
.map((val, index) => ({
letter: val.text,
delta,
index
})));
})
.flatMap(letterConfig => {
return Observable
.timer( (letterConfig.index + 1) * 100)
.map(() => ({
text: letterConfig.letter,
top: letterConfig.delta.offsetY,
left: letterConfig.delta.offsetX + letterConfig.index * 20 + 20,
index: letterConfig.index
}));
})
.subscribe(letterConfig => {
// to render the letters, put them back into app zone
this.zone.run(() => this.letters[letterConfig.index] = letterConfig);
});
});//zone
}
}