Skip to content

Commit

Permalink
fix(tabs): adding tab content to DOM just if selected tab (#1422)
Browse files Browse the repository at this point in the history
  • Loading branch information
Liudmila Lysenko committed Jan 9, 2019
1 parent ac55b08 commit 9f2bcf8
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<tabset [dynamic]="true">
<tab heading="Title" id="tab1">Dynamic insert content</tab>
<tab heading="Title 1">Dynamic insert content 1</tab>
<tab heading="Title 2">Dynamic insert content 2</tab>
</tabset>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Component } from '@angular/core';

@Component({
selector: 'demo-tabs-dynamic-insert',
templateUrl: './dynamic-insert.html'
})
export class DemoTabsDynamicInsertComponent {}
4 changes: 3 additions & 1 deletion demo/src/app/components/+tabs/demos/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { DemoTabsDisabledComponent } from './disabled/disabled';
import { DemoTabsCustomComponent } from './custom-template/custom-template';
import { DemoTabsSelectEventComponent } from './select-event/select-event';
import { DemoAccessibilityComponent } from './accessibility/accessibility';
import { DemoTabsDynamicInsertComponent } from "./dynamic-insert/dynamic-insert";

export const DEMO_COMPONENTS = [
DemoTabsBasicComponent,
Expand All @@ -23,5 +24,6 @@ export const DEMO_COMPONENTS = [
DemoTabsConfigComponent,
DemoTabsCustomComponent,
DemoTabsSelectEventComponent,
DemoAccessibilityComponent
DemoAccessibilityComponent,
DemoTabsDynamicInsertComponent
];
11 changes: 11 additions & 0 deletions demo/src/app/components/+tabs/tabs-section.list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { DemoTabsDisabledComponent } from './demos/disabled/disabled';
import { DemoTabsCustomComponent } from './demos/custom-template/custom-template';
import { DemoTabsSelectEventComponent } from './demos/select-event/select-event';
import { DemoAccessibilityComponent } from './demos/accessibility/accessibility';
import { DemoTabsDynamicInsertComponent } from './demos/dynamic-insert/dynamic-insert';

import { ContentSection } from '../../docs/models/content-section.model';
import { DemoTopSectionComponent } from '../../docs/demo-section-components/demo-top-section/index';
Expand Down Expand Up @@ -63,6 +64,16 @@ export const demoComponentContent: ContentSection[] = [
html: require('!!raw-loader?lang=markup!./demos/dynamic/dynamic.html'),
outlet: DemoTabsDynamicComponent
},
{
title: 'Dynamic insert tabs content into DOM',
anchor: 'dynamic-insert',
component: require('!!raw-loader?lang=typescript!./demos/dynamic-insert/dynamic-insert'),
html: require('!!raw-loader?lang=markup!./demos/dynamic-insert/dynamic-insert.html'),
description: `<p>By default, the tabs contents are added into DOM when page is loaded, for all tabs even not
selected. Dynamic insert tabs into DOM will initialize and add the tab directives only when the tab is activated.
Tab contents can be dynamic insert by declaring the tabset component with attribute <code>[dynamic]="true"</code>.</p>`,
outlet: DemoTabsDynamicInsertComponent
},
{
title: 'Pills',
anchor: 'tabs-Pills',
Expand Down
5 changes: 5 additions & 0 deletions demo/src/ng-api-doc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2792,6 +2792,11 @@ export const ngdoc: any = {
"name": "vertical",
"type": "boolean",
"description": "<p>if true tabs will be placed vertically </p>\n"
},
{
"name": "dynamic",
"type": "boolean",
"description": "<p>if true, tab content will be insert into DOM only if tab is selected</p>\n"
}
],
"outputs": [],
Expand Down
1 change: 1 addition & 0 deletions src/tabs/tab.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export class TabDirective implements OnInit, OnDestroy {
@Input() disabled: boolean;
/** if true tab can be removable, additional button will appear */
@Input() removable: boolean;

/** if set, will be added to the tab's class attribute. Multiple classes are supported. */
@Input()
get customClass(): string {
Expand Down
20 changes: 14 additions & 6 deletions src/tabs/tabset.component.html
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
<ul class="nav" [ngClass]="classMap" (click)="$event.preventDefault()">
<li *ngFor="let tabz of tabs" [ngClass]="['nav-item', tabz.customClass || '']"
[class.active]="tabz.active" [class.disabled]="tabz.disabled">
<li *ngFor="let tabz of tabs"
[ngClass]="['nav-item', tabz.customClass || '']"
[class.active]="tabz.active"
[class.disabled]="tabz.disabled">
<a href="javascript:void(0);" class="nav-link"
[attr.id]="tabz.id ? tabz.id + '-link' : ''"
[class.active]="tabz.active" [class.disabled]="tabz.disabled"
(click)="tabz.active = true">
[class.active]="tabz.active"
[class.disabled]="tabz.disabled"
(click)="selectTab(tabz)">
<span [ngTransclude]="tabz.headingRef">{{ tabz.heading }}</span>
<span *ngIf="tabz.removable" (click)="$event.preventDefault(); removeTab(tabz);" class="bs-remove-tab"> &#10060;</span>
<span *ngIf="tabz.removable" (click)="$event.preventDefault(); removeTab(tabz);" class="bs-remove-tab">
&#10060;
</span>
</a>
</li>
</ul>

<div class="tab-content">
<ng-content></ng-content>
<ng-container *ngIf="!dynamic">
<ng-content></ng-content>
</ng-container>
</div>
44 changes: 41 additions & 3 deletions src/tabs/tabset.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
import { Component, HostBinding, Input, OnDestroy, Renderer2 } from '@angular/core';
import {
AfterContentInit,
Component,
ContentChild,
ElementRef,
forwardRef,
HostBinding,
Input,
OnDestroy,
Renderer2
} from '@angular/core';

import { TabDirective } from './tab.directive';
import { TabsetConfig } from './tabset.config';
Expand All @@ -8,12 +18,13 @@ import { TabsetConfig } from './tabset.config';
selector: 'tabset',
templateUrl: './tabset.component.html'
})
export class TabsetComponent implements OnDestroy {
export class TabsetComponent implements OnDestroy, AfterContentInit {
/** if true tabs will be placed vertically */
@Input()
get vertical(): boolean {
return this._vertical;
}

set vertical(value: boolean) {
this._vertical = value;
this.setClassMap();
Expand All @@ -24,6 +35,7 @@ export class TabsetComponent implements OnDestroy {
get justified(): boolean {
return this._justified;
}

set justified(value: boolean) {
this._justified = value;
this.setClassMap();
Expand All @@ -34,12 +46,17 @@ export class TabsetComponent implements OnDestroy {
get type(): string {
return this._type;
}

set type(value: string) {
this._type = value;
this.setClassMap();
}

/** if true, tab content will be inject to DOM only if tab is selected */
@Input() dynamic = false;

@HostBinding('class.tab-container') clazz = true;
@ContentChild(forwardRef(() => TabDirective)) content: TabDirective;

tabs: TabDirective[] = [];
classMap: { [key: string]: boolean } = {};
Expand All @@ -49,14 +66,35 @@ export class TabsetComponent implements OnDestroy {
protected _justified: boolean;
protected _type: string;

constructor(config: TabsetConfig, private renderer: Renderer2) {
constructor(config: TabsetConfig, private renderer: Renderer2, private elRef: ElementRef) {
Object.assign(this, config);
}

ngAfterContentInit() {
if (this.dynamic && typeof this.content !== 'undefined') {
const container = this.elRef.nativeElement.querySelector('.tab-content');
this.renderer.appendChild(container, this.content.elementRef.nativeElement);
}
}

ngOnDestroy(): void {
this.isDestroyed = true;
}

selectTab(selectedTab: TabDirective): void {
selectedTab.active = true;

if (this.dynamic) {
const container = this.elRef.nativeElement.querySelector('.tab-content');

while (container.firstChild) {
container.firstChild.remove();
}

this.renderer.appendChild(container, selectedTab.elementRef.nativeElement);
}
}

addTab(tab: TabDirective): void {
this.tabs.push(tab);
tab.active = this.tabs.length === 1 && typeof tab.active === 'undefined';
Expand Down

0 comments on commit 9f2bcf8

Please sign in to comment.