From 457c32aec3b668d1852d1b813b5a834748dc5ffd Mon Sep 17 00:00:00 2001 From: Mila Date: Fri, 8 Feb 2019 12:50:16 +0200 Subject: [PATCH] fix(tabs): adding tab content to DOM just if selected tab (#1422) (#4991) Fixes #1422 --- .../demos/dynamic-insert/dynamic-insert.html | 5 +++ .../demos/dynamic-insert/dynamic-insert.ts | 7 +++ demo/src/app/components/+tabs/demos/index.ts | 4 +- .../app/components/+tabs/tabs-section.list.ts | 11 +++++ demo/src/ng-api-doc.ts | 5 +++ src/spec/tabset.component.spec.ts | 1 + src/tabs/tab.directive.ts | 1 + src/tabs/tabset.component.html | 20 ++++++--- src/tabs/tabset.component.ts | 44 +++++++++++++++++-- 9 files changed, 88 insertions(+), 10 deletions(-) create mode 100644 demo/src/app/components/+tabs/demos/dynamic-insert/dynamic-insert.html create mode 100644 demo/src/app/components/+tabs/demos/dynamic-insert/dynamic-insert.ts diff --git a/demo/src/app/components/+tabs/demos/dynamic-insert/dynamic-insert.html b/demo/src/app/components/+tabs/demos/dynamic-insert/dynamic-insert.html new file mode 100644 index 0000000000..ad130d1d9b --- /dev/null +++ b/demo/src/app/components/+tabs/demos/dynamic-insert/dynamic-insert.html @@ -0,0 +1,5 @@ + + Dynamic insert content + Dynamic insert content 1 + Dynamic insert content 2 + diff --git a/demo/src/app/components/+tabs/demos/dynamic-insert/dynamic-insert.ts b/demo/src/app/components/+tabs/demos/dynamic-insert/dynamic-insert.ts new file mode 100644 index 0000000000..74ca2f3430 --- /dev/null +++ b/demo/src/app/components/+tabs/demos/dynamic-insert/dynamic-insert.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'demo-tabs-dynamic-insert', + templateUrl: './dynamic-insert.html' +}) +export class DemoTabsDynamicInsertComponent {} diff --git a/demo/src/app/components/+tabs/demos/index.ts b/demo/src/app/components/+tabs/demos/index.ts index efa15a1a81..50bd9fcbf5 100644 --- a/demo/src/app/components/+tabs/demos/index.ts +++ b/demo/src/app/components/+tabs/demos/index.ts @@ -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, @@ -23,5 +24,6 @@ export const DEMO_COMPONENTS = [ DemoTabsConfigComponent, DemoTabsCustomComponent, DemoTabsSelectEventComponent, - DemoAccessibilityComponent + DemoAccessibilityComponent, + DemoTabsDynamicInsertComponent ]; diff --git a/demo/src/app/components/+tabs/tabs-section.list.ts b/demo/src/app/components/+tabs/tabs-section.list.ts index ad73ff1691..5e9b46e4f1 100644 --- a/demo/src/app/components/+tabs/tabs-section.list.ts +++ b/demo/src/app/components/+tabs/tabs-section.list.ts @@ -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'; @@ -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: `

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 [dynamic]="true".

`, + outlet: DemoTabsDynamicInsertComponent + }, { title: 'Pills', anchor: 'tabs-Pills', diff --git a/demo/src/ng-api-doc.ts b/demo/src/ng-api-doc.ts index 3070bffd38..42a0260ac2 100644 --- a/demo/src/ng-api-doc.ts +++ b/demo/src/ng-api-doc.ts @@ -2925,6 +2925,11 @@ export const ngdoc: any = { "name": "vertical", "type": "boolean", "description": "

if true tabs will be placed vertically

\n" + }, + { + "name": "dynamic", + "type": "boolean", + "description": "

if true, tab content will be insert into DOM only if tab is selected

\n" } ], "outputs": [], diff --git a/src/spec/tabset.component.spec.ts b/src/spec/tabset.component.spec.ts index c0cd5d7727..f6bee87905 100644 --- a/src/spec/tabset.component.spec.ts +++ b/src/spec/tabset.component.spec.ts @@ -135,6 +135,7 @@ describe('Component: Tabs', () => { it('should mark the requested tab as active', () => { context.tabs[0].active = true; + context.tabset.selectTab(context.tabset.tabs[0]); fixture.detectChanges(); expectActiveTabs(element, [false, true, false, false]); }); diff --git a/src/tabs/tab.directive.ts b/src/tabs/tab.directive.ts index 04a18d961c..63c0bcc5ca 100644 --- a/src/tabs/tab.directive.ts +++ b/src/tabs/tab.directive.ts @@ -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 { diff --git a/src/tabs/tabset.component.html b/src/tabs/tabset.component.html index e1fce585a8..f713d0a052 100644 --- a/src/tabs/tabset.component.html +++ b/src/tabs/tabset.component.html @@ -1,15 +1,23 @@ +
- + + +
diff --git a/src/tabs/tabset.component.ts b/src/tabs/tabset.component.ts index 25f2072bef..216e24df3b 100644 --- a/src/tabs/tabset.component.ts +++ b/src/tabs/tabset.component.ts @@ -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'; @@ -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(); @@ -24,6 +35,7 @@ export class TabsetComponent implements OnDestroy { get justified(): boolean { return this._justified; } + set justified(value: boolean) { this._justified = value; this.setClassMap(); @@ -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 } = {}; @@ -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';