All Components

Load Tabs on Demand

The TabStrip provides default options for creating and managing the content of its tabs.

By default, the component either creates the content of all its tabs when it is initialized or creates the content of each tab when the tab becomes active. When the tab is not in use anymore, the TabStrip destroys it. This specific default behavior depends on the value of the keepTabContent option.

To combine both approaches of loading the tab content on demand when a tab becomes active and keeping the tab content when the tab is no longer active, create a custom structural directive that can be placed in the content template of the tab.

// tslint:disable:max-line-length
/*
Load-on-demand directive code and comments courtesy of our esteemed customer Balazs Hideghety.
*/

import {AfterViewInit, Directive, OnDestroy, OnInit, Optional, TemplateRef, ViewContainerRef} from '@angular/core';
import {Subscription} from 'rxjs/Subscription';

import {TabStripComponent, TabStripTabComponent} from '@progress/kendo-angular-layout';

/*
USAGE:      Import the module/directive and add *loadOnDemand structural directive to the Kendo Tab content <ng-template>.

IMPORTANT:  Set [keepTabContent]="true", otherwise the selected tab will be destroyed when a new selection is made.
            Currently this directive implementation sets this value for us.

HTML sample:
<kendo-tabstrip [keepTabContent]="true">
    <kendo-tabstrip-tab [title]="'Paris'" [selected]="true">
        <ng-template kendoTabContent *loadOnDemand>
            ...
        </ng-template>
    </kendo-tabstrip-tab>
    <kendo-tabstrip-tab [title]="'New York City'">
        <ng-template kendoTabContent *loadOnDemand>
            ...
        </ng-template>
    </kendo-tabstrip-tab>

    ...
*/
@Directive({
    selector: '[loadOnDemand]'
})
export class TabContentLoadOnDemandDirective implements OnInit, AfterViewInit, OnDestroy {
    protected s: Subscription;
    protected wasLoaded: boolean;

    constructor(@Optional() private tabStripComponent: TabStripComponent,
                @Optional() private tabStripTabComponent: TabStripTabComponent,
                private templateRef: TemplateRef<any>,
                private viewContainer: ViewContainerRef) {

        // #1 Initialize only if it is inside of a kendo TabStrip component
        if (!this.tabStripComponent || !tabStripTabComponent) {
            return;
        }

        // #2 Unload - is not necessary as a structural directive is responsible for creating and destroying content (so no "auto" create will occur)

        // #3
        // We need to keep tab content (once loaded) to have benefits of using load-on-demand, so I do set it here.
        // Also setting this inside CTOR has the benefits of user to be able to change value via binding... even if it leads to weird effects (load on demand not working as expected).
        this.tabStripComponent.keepTabContent = true;
    }

    public ngOnInit(): void {

        // NOTE: we could do a check if this.tabStripComponent.keepTabContent is truthy, if not, we'd raise an error... or log a warning.
        /*
        if (!this.tabStripComponent.keepTabContent)
            console.warn(`The *loadOnDemand directive on tab panel: '${this.tabStripTabComponent.title}' is ineffective, cause the tab component uses {keepTabContent]="false" which destroys components!`)
        */

        this.s = new Subscription()
            .add(this.tabStripComponent.tabSelect.subscribe(this.tabSelectEx.bind(this)));
    }

    public ngAfterViewInit(): void {
        if (this.tabStripTabComponent.active) {
            this.loadMe();
        }
    }

    public ngOnDestroy(): void {
        this.s.unsubscribe();
    }

    protected loadMe(): void {
        if (!this.wasLoaded) {
            this.wasLoaded = true;
            this.viewContainer.createEmbeddedView(this.templateRef);
        }
    }

    protected unloadMe(): void {
        if (this.wasLoaded) {
            this.wasLoaded = false;
            this.viewContainer.clear();
        }
    }

    protected tabSelectEx(e: any): void {
        if (e.title === this.tabStripTabComponent.title) {
            this.loadMe();
        }
    }
}
// tslint:disable:max-line-length
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
      <kendo-tabstrip [keepTabContent]="true">
        <kendo-tabstrip-tab [title]="'Paris'" [selected]="true">
          <ng-template kendoTabContent *loadOnDemand>
            <p>
              Paris is the capital and most populous city of France. It has an area of 105 square kilometres (41 square miles) and a population in 2013 of 2,229,621 within its administrative limits. The city is both a commune and department, and forms the centre and headquarters of the Île-de-France, or Paris Region, which has an area of 12,012 square kilometres (4,638 square miles) and a population in 2014 of 12,005,077, comprising 18.2 percent of the population of France.
            </p>
          </ng-template>
        </kendo-tabstrip-tab>
        <kendo-tabstrip-tab [title]="'New York City'">
          <ng-template kendoTabContent *loadOnDemand>
            <p>
              The City of New York, often called New York City or simply New York, is the most populous city in the United States. With an estimated 2015 population of 8,550,405 distributed over a land area of just 305 square miles (790 km2), New York City is also the most densely populated major city in the United States. Located at the southern tip of the state of New York, the city is the center of the New York metropolitan area, one of the most populous urban agglomerations in the world.
            </p>
            <p>
              A global power city, New York City exerts a significant impact upon commerce, finance, media, art, fashion, research, technology, education, and entertainment, its fast pace defining the term New York minute. Home to the headquarters of the United Nations, New York is an important center for international diplomacy and has been described as the cultural and financial capital of the world.
            </p>
          </ng-template>
        </kendo-tabstrip-tab>
        <kendo-tabstrip-tab [title]="'Tallinn'">
          <ng-template kendoTabContent *loadOnDemand>
            <p>
              Tallinn is the capital and largest city of Estonia. It is situated on the northern coast of the country, on the shore of the Gulf of Finland, 80 km (50 mi) south of Helsinki, east of Stockholm and west of Saint Petersburg. From the 13th century until 1918 (and briefly during the Nazi occupation of Estonia from 1941 to 1944), the city was known as Reval. Tallinn occupies an area of 159.2 km2 (61.5 sq mi) and has a population of 443,894. Approximately 32% of Estonia's total population lives in Tallinn.
            </p>
            <p>
              Tallinn was founded in 1248, but the earliest human settlements are over 5,000 years old, making it one of the oldest capital cities of Northern Europe. Due to its strategic location, the city became a major trade hub, especially from the 14th to the 16th century, when it grew in importance as part of the Hanseatic League.
            </p>
          </ng-template>
        </kendo-tabstrip-tab>
      </kendo-tabstrip>
    `,
    styles: [`
        kendo-tabstrip p {
            margin: 0;
            padding: 8px;
        }
    `]
})
export class AppComponent {
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { LayoutModule } from '@progress/kendo-angular-layout';
import { TabContentLoadOnDemandDirective } from './lazyload.directive';
import { TabStripComponent, TabStripTabComponent } from '@progress/kendo-angular-layout';
import { AppComponent } from './app.component';

@NgModule({
  imports: [ BrowserModule, BrowserAnimationsModule, LayoutModule ],
  declarations: [ AppComponent, TabContentLoadOnDemandDirective ],
  entryComponents: [ TabStripComponent, TabStripTabComponent ],
  bootstrap: [ AppComponent ]
})

export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

enableProdMode();

const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);
In this article