Issue
I have an Angular2 master component which includes a number of child components and an independant countdown component (named "clock" in the code below). Countdown component changes it's label every second and that causes the master component and all others to (needlessly) re-render. How can I prevent that? This is the source of my countdown component:
import {Component, Input} from 'angular2/core';
@Component({
selector: 'clock',
template: `
<span>
{{caption}}
</span>
`
})
export class ClockComponent {
public caption;
@Input('seconds') seconds :number = 0;
constructor() {
var self = this;
setInterval(function(){
self.seconds--;
self.caption = self.getCaption(self.seconds);
}, 1000);
this.caption = this.getCaption(this.seconds);
}
getCaption (seconds): string {
let h = Math.floor(seconds / (60*60));
let m = Math.floor((seconds - 60 * 60 * h) / 60);
let s = seconds % 60;
return ((h < 10) ? '0' : '') + h + ':'
+ ((m < 10) ? '0' : '') + m + ':'
+ ((s < 10) ? '0' : '') + s ;
}
}
and you can imagine it being embedded alongside others in "my-app"; something like:
<clock [seconds]="1800"></clock>
<other-comps>...</other-comps>...
EDIT (per comment): When I mean re-render, this is what happens: I've added a console.log printout to other components (nav and question, see image below) on various rendering actions, for instance, a component has a class binder, eg: [class.selected]="isSelected" and I've added console.log() to the isSelected() method and can thus spot that it is called every one second, every time the countdown (clock) refreshes itself. I'd like for the countdown to change label (count down from eg 30 minutes) WITHOUT affecting nav and question components and causing them to re-render.
EDIT (2):
And here is the plunker: http://plnkr.co/edit/PwBfUQXyZyTrqPaqrwRm?p=preview
Fire up the console and watch for six those "q-nav isSelected?" appearing every second (printed from qnav component).
Solution
That's Angular's change detection that is invoked on every event, and setInterval
calling the callback is such an event.
You can switch change detection to OnPush
so change detection only takes place when an @Input()
is updated or when you invoke change detection explicitly, for example by calling methods on ChangeDetectorRefs
import {Component, Input, OnInit, EventEmitter, Output, OnChanges, ChangeDetectionStrategy} from 'angular2/core';
@Component({
selector: 'q-nav',
template: `
<span *ngFor="#a of currAnswers; #i = index" class="aii-qn"
[class.selected]="isSelected(i)"
(click)="onSelect(i)">
<span class="badge">{{ i+1 }}</span>
</span>
`,
styles: [`
.aii-qn {
color: #0000ff;
cursor: pointer;
font-size: 2rem;
}
.selected {
border: black solid 2px;
}
`],
changeDetection: ChangeDetectionStrategy.OnPush
})
For more details see:
http://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html
Answered By - Günter Zöchbauer
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.