Skip to content

Commit

Permalink
fix(tabset): lazy loading (#2827)
Browse files Browse the repository at this point in the history
  • Loading branch information
evtkhvch committed Nov 15, 2021
1 parent 1447b15 commit a51513c
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 42 deletions.
11 changes: 11 additions & 0 deletions src/framework/theme/components/tabset/tab-content.directive.ts
@@ -0,0 +1,11 @@
import { Directive, TemplateRef } from '@angular/core';

/**
* Directive to wrap tab lazy content.
* */
@Directive({
selector: '[nbTabContent]',
})
export class NbTabContentDirective {
constructor(public templateRef: TemplateRef<any>) {}
}
80 changes: 54 additions & 26 deletions src/framework/theme/components/tabset/tabset.component.ts
Expand Up @@ -15,13 +15,15 @@ import {
AfterContentInit,
HostBinding,
ChangeDetectorRef,
ContentChild,
} from '@angular/core';
import { ActivatedRoute } from '@angular/router';

import { convertToBoolProperty, NbBooleanInput } from '../helpers';
import { NbComponentOrCustomStatus } from '../component-status';
import { NbBadgePosition } from '../badge/badge.component';
import { NbIconConfig } from '../icon/icon.component';
import { NbTabContentDirective } from './tab-content.directive';

/**
* Specific tab container.
Expand All @@ -32,17 +34,23 @@ import { NbIconConfig } from '../icon/icon.component';
* badgeStatus="danger">
* <p>List of <strong>users</strong>.</p>
* </nb-tab>
```
* ```
*/
@Component({
selector: 'nb-tab',
template: `
<ng-container *ngIf="init">
<ng-container
*ngIf="tabContentDirective; else projectedContent"
[ngTemplateOutlet]="tabContentDirective.templateRef"
></ng-container>
<ng-template #projectedContent>
<ng-content></ng-content>
</ng-container>
</ng-template>
`,
})
export class NbTabComponent {
@ContentChild(NbTabContentDirective) tabContentDirective: NbTabContentDirective;

/**
* Tab title
Expand Down Expand Up @@ -133,8 +141,9 @@ export class NbTabComponent {

/**
* Lazy load content before tab selection
* TODO: rename, as lazy is by default, and this is more `instant load`
* @param {boolean} val
* @docs-private
* @deprecated This setting never worked. Wrap content into a `nbTabContent` to make it lazy.
* @breaking-change Remove 10.0.0
*/
@Input()
set lazyLoad(val: boolean) {
Expand Down Expand Up @@ -164,6 +173,11 @@ export class NbTabComponent {
*/
@Input() badgePosition: NbBadgePosition;

/**
* @deprecated
* @breaking-change Remove 10.0.0
* @docs-private
*/
init: boolean = false;
}

Expand Down Expand Up @@ -214,12 +228,26 @@ export class NbTabComponent {
* (`tabset-tab-text-hide-breakpoint` property) for better responsive behaviour.
* You can open the following example and make
* your screen smaller - titles will be hidden in the last tabset in the list:
*
* @stacked-example(Icon, tabset/tabset-icon.component)
*
* It is also possible to disable a tab using `disabled` property:
* @stacked-example(Disabled Tab, tabset/tabset-disabled.component)
*
* By default, the tab contents instantiated straightaway. To make tab contents load lazy,
* declare the body of a tab in a template with `nbTabContent` directive.
* ```html
* <nb-tabset>
* <nb-tab>
* <some-component *nbTabContent>Lazy content</some-component>
* </nb-tab>
* <nb-tab>
* <ng-template nbTabContent>
* Lazy content with template syntax
* </ng-template>
* </nb-tab>
* </nb-tabset>
* ```
*
* @styles
*
* tabset-background-color:
Expand Down Expand Up @@ -267,33 +295,36 @@ export class NbTabComponent {
styleUrls: ['./tabset.component.scss'],
template: `
<ul class="tabset">
<li *ngFor="let tab of tabs"
(click)="selectTab(tab)"
(keyup.space)="selectTab(tab)"
(keyup.enter)="selectTab(tab)"
[class.responsive]="tab.responsive"
[class.active]="tab.active"
[class.disabled]="tab.disabled"
[attr.tabindex]="tab.disabled ? -1 : 0"
[attr.data-tab-id]="tab.tabId"
class="tab">
<li
*ngFor="let tab of tabs"
(click)="selectTab(tab)"
(keyup.space)="selectTab(tab)"
(keyup.enter)="selectTab(tab)"
[class.responsive]="tab.responsive"
[class.active]="tab.active"
[class.disabled]="tab.disabled"
[attr.tabindex]="tab.disabled ? -1 : 0"
[attr.data-tab-id]="tab.tabId"
class="tab"
>
<a href (click)="$event.preventDefault()" tabindex="-1" class="tab-link">
<nb-icon *ngIf="tab.tabIcon" [config]="tab.tabIcon"></nb-icon>
<span *ngIf="tab.tabTitle" class="tab-text">{{ tab.tabTitle }}</span>
</a>
<nb-badge *ngIf="tab.badgeText || tab.badgeDot"
<nb-badge
*ngIf="tab.badgeText || tab.badgeDot"
[text]="tab.badgeText"
[dotMode]="tab.badgeDot"
[status]="tab.badgeStatus"
[position]="tab.badgePosition">
[position]="tab.badgePosition"
>
</nb-badge>
</li>
</ul>
<ng-content select="nb-tab"></ng-content>
`,
})
export class NbTabsetComponent implements AfterContentInit {

@ContentChildren(NbTabComponent) tabs: QueryList<NbTabComponent>;

@HostBinding('class.full-width')
Expand Down Expand Up @@ -321,17 +352,14 @@ export class NbTabsetComponent implements AfterContentInit {
*/
@Output() changeTab = new EventEmitter<any>();

constructor(private route: ActivatedRoute,
private changeDetectorRef: ChangeDetectorRef) {
}
constructor(private route: ActivatedRoute, private changeDetectorRef: ChangeDetectorRef) {}

// TODO: refactoring this component, avoid change detection loop
ngAfterContentInit() {
this.route.params
.pipe(
map(
(params: any) =>
this.tabs.find((tab) => this.routeParam ? tab.route === params[this.routeParam] : tab.active),
map((params: any) =>
this.tabs.find((tab) => (this.routeParam ? tab.route === params[this.routeParam] : tab.active)),
),
delay(0),
map((tab: NbTabComponent) => tab || this.tabs.first),
Expand All @@ -346,7 +374,7 @@ export class NbTabsetComponent implements AfterContentInit {
// TODO: navigate to routeParam
selectTab(selectedTab: NbTabComponent) {
if (!selectedTab.disabled) {
this.tabs.forEach(tab => tab.active = tab === selectedTab);
this.tabs.forEach((tab) => (tab.active = tab === selectedTab));
this.changeTab.emit(selectedTab);
}
}
Expand Down
24 changes: 8 additions & 16 deletions src/framework/theme/components/tabset/tabset.module.ts
Expand Up @@ -11,23 +11,15 @@ import { NbSharedModule } from '../shared/shared.module';
import { NbTabsetComponent, NbTabComponent } from './tabset.component';
import { NbBadgeModule } from '../badge/badge.module';
import { NbIconModule } from '../icon/icon.module';
import { NbTabContentDirective } from './tab-content.directive';

const NB_TABSET_COMPONENTS = [
NbTabsetComponent,
NbTabComponent,
];
const NB_TABSET_COMPONENTS = [NbTabsetComponent, NbTabComponent];

const NB_TABSET_DIRECTIVES = [NbTabContentDirective];

@NgModule({
imports: [
NbSharedModule,
NbBadgeModule,
NbIconModule,
],
declarations: [
...NB_TABSET_COMPONENTS,
],
exports: [
...NB_TABSET_COMPONENTS,
],
imports: [NbSharedModule, NbBadgeModule, NbIconModule],
declarations: [...NB_TABSET_COMPONENTS, ...NB_TABSET_DIRECTIVES],
exports: [...NB_TABSET_COMPONENTS, ...NB_TABSET_DIRECTIVES],
})
export class NbTabsetModule { }
export class NbTabsetModule {}
1 change: 1 addition & 0 deletions src/framework/theme/public_api.ts
Expand Up @@ -80,6 +80,7 @@ export * from './components/tabset/tabset.module';
export * from './components/datepicker/date-timepicker.component';
export * from './components/datepicker/calendar-with-time.component';
export * from './components/tabset/tabset.component';
export * from './components/tabset/tab-content.directive';
export * from './components/user/user.module';
export * from './components/user/user.component';
export * from './components/actions/actions.module';
Expand Down

0 comments on commit a51513c

Please sign in to comment.