Reputation: 324
I have a tabbed UI using a very simple approach like this:
<div *ngIf="active" class="pane">
<ng-content></ng-content>
</div>
Active is set to true on the component when the tab becomes selected.
There are multiple components in the tabs that all poll data from a webservice, the relevant code:
export class DebugComponent implements OnInit {
public timerSubscription: Subscription;
ngOnInit() {
this.startTimer(0);
}
private startTimer(delay: number){
let timer = Observable.timer(delay, 1000);
this.timerSubscription = timer.subscribe(x => this.execute());
}
private stopTimer(){
this.timerSubscription.unsubscribe();
}
execute() {
this.stopTimer();
// do stuff
this.startTimer(5);
}
}
While it works well to start the timer using ngOnInit, I have found no way to stop it when the component gets removed from the visible DOM.
What would be the best approach to get notified when the component gets removed from the visible DOM by the ngIf condition to stop the timer?
Thanks,
Thanks to Günter, I figured out the solution to the problem. As I believe this to be a common requirement, I'll try to put all the pieces together here (not full copy and paste ready code, but all the needed parts):
A simple tab component, based on this http://blog.thoughtram.io/angular/2015/04/09/developing-a-tabs-component-in-angular-2.html:
The main tabs component containing the tabs:
tabs-component.ts
import {Component, ContentChildren, QueryList, AfterContentInit} from '@angular/core';
import {TabComponent} from './tab.component';
@Component({
selector: 'tabs',
template: `
<ul class="nav nav-tabs">
<li *ngFor="let tab of tabs" (mouseup)="selectTab(tab)" [class.active]="tab.active">
<a href="#">{{tab.title}}</a>
</li>
</ul>
<ng-content></ng-content>
`
})
export class TabsComponent implements AfterContentInit {
@ContentChildren(TabComponent) tabs: QueryList<TabComponent>;
// contentChildren are set
ngAfterContentInit() {
// get all active tabs
let activeTabs = this.tabs.filter((tab) => tab.active);
// if there is no active tab set, activate the first
if (activeTabs.length === 0) {
this.selectTab(this.tabs.first);
}
}
selectTab(selectedTab: TabComponent) {
// deactivate active tab
this.tabs.filter((tab) => tab.active).forEach(tab => tab.disable());
// activate the tab the user has clicked on.
selectedTab.activate();
}
}
The tab component to put inside the tabs component:
tab-component.ts
import {Component, Input, ContentChildren, QueryList} from '@angular/core';
import {TabChild} from "./tab.child";
@Component({
selector: 'tab',
styles: [`
.pane{
padding: 1em;
}
`],
template: `
<div *ngIf="active" class="pane">
<ng-content></ng-content>
</div>
`
})
export class TabComponent {
@Input('tabTitle') title: string;
@Input() active = false;
@ContentChildren(TabChild) content:QueryList<TabChild>;
public activate(){
this.active = true;
this.content.toArray().forEach(dc => dc.tabActivated());
}
public disable(){
this.active = false;
this.content.toArray().forEach(dc => dc.tabDisabled());
}
}
The components to display inside the tabs need to inherit from this base class:
tab-child.ts
import {Directive} from "@angular/core";
@Directive({selector: "TabChild"})
export class TabChild {
public tabActivated() : void{}
public tabDisabled() : void{}
}
A sample component looks like this:
sample-component.ts
import {Component, ApplicationRef, forwardRef} from '@angular/core';
import {TabChild} from "./tab.child";
@Component({
selector: 'sample',
templateUrl: "app/sample.component.html",
providers: [{provide: TabChild, useExisting: forwardRef(() => SampleComponent) }]
})
export class SampleComponent implements TabChild {
tabActivated(): void {
console.log("Sample tabActivated");
}
tabDisabled(): void {
console.log("Sample tabDisabled");
}
}
Putting it all together:
@Component({
selector: "my-app",
template: `<tabs>
<tab tabTitle="Sample1">
<sample></sample>
</tab>
<tab tabTitle="Sample2">
<sample></sample>
</tab>
</tabs>`
})
Upvotes: 2
Views: 3822
Reputation: 657506
You can use the ngOnDestroy
lifecycle callback
export class DebugComponent implements OnInit, OnDestroy {
ngOnDestroy() {
this.stopTimer();
}
See also https://angular.io/docs/ts/latest/api/core/index/OnDestroy-class.html
Upvotes: 1