1

I have a fairly big list of data and every element has a filter applied. For performance reasons (I want to add a lot of attributes to each entry) I only want to update the list when data changes (it's fine if updating it is unperformant). Unfortunately, the OnPush ChangeStrategy in Angular 2 still updates whenever I click on something.

Is there a way to ONLY manually trigger updates/checks (using for example changeDetectorRef.markForCheck())and not have it automatic on every click event?

Both AngularJS (1.5) and Angular 2 are fine.

Luxalpa
  • 430
  • 4
  • 15
  • Change detection in Angular2 is vastly more efficient than in AngularJS1.x. Are you certain it won't meet your needs with an OnPush ChangeStrategy? – David L Mar 26 '16 at 02:43
  • See this [answer](http://stackoverflow.com/questions/34827334/triggering-angular2-change-detection-manually) – Eric Martinez Mar 26 '16 at 02:53
  • @EricMartinez I saw that post before, but the problem is, that only triggers an ADDITIONAL change detection. However, I want to get rid of all the unnecessary change detections. In my case I have a pure pipe which always triggers when the change detection triggers. – Luxalpa Mar 26 '16 at 02:55
  • Try [detach()](https://angular.io/docs/ts/latest/api/core/ChangeDetectorRef-class.html#!#detach), and manually adding any click handlers in [afterViewInit()](https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html#!#afterview) using [runOutsideAngular()](https://angular.io/docs/ts/latest/api/core/NgZone-class.html#!#runOutsideAngular) and addEventListener() -- i.e., don't use `(click)` in your template. Call detectChanges() when you want to manually run changed detection. I have no idea if this will work. – Mark Rajcok Mar 26 '16 at 04:17
  • @MarkRajcok it seems like it's not possible to call `detectChanges()` with a detached changeDetector. Now I tried a reattach + detach which seems to work but does everything twice (even in prod mode). – Luxalpa Mar 26 '16 at 07:53

1 Answers1

1

This should work (at least it does in this Plunker):

@Component({
  selector: 'manual',
  template: `<br>manual: {{_counter.obj.counter}}
  <br><button (click)="0">click me</button>
    <li *ngFor="#item of items">{{item}}</li>`,
})
export class Manual {
  items = 'one two'.split(' ');
  constructor(private ref: ChangeDetectorRef, private _counter:Counter) {}
  ngOnInit() {
     this.ref.detach();
     setInterval(_ => {
        this.items.push(`CD ran when counter=${this._counter.obj.counter}`);
        this.ref.reattach();
        this.ref.detectChanges();
        this.ref.detach();
     }, 3000);
  }
}

In the plunker I have a Counter service that updates obj.counter every second. In the Manual component, {{_counter.obj.counter}} (hence the view) only updates when detectChanges() is called – every 3 seconds. Clicking the click me button does not cause the view to update, as desired.

I did not specify OnPush. However, if you do, it does not seem to alter the desired operation.

In the plunker I also have an Automatic component, and its {{_counter.obj.counter}} (hence its view) updates every second, as expected.

Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492