From ea6c817fc4f1692389cf8f26b3cf2ac9c085a902 Mon Sep 17 00:00:00 2001 From: Jeremy Elbourn Date: Sat, 29 Oct 2016 07:57:21 -0700 Subject: [PATCH] feat(tabs): simplify api (#1645) --- src/demo-app/tabs/tabs-demo.html | 35 +++++++++------ src/demo-app/tabs/tabs-demo.ts | 12 +++--- src/lib/tabs/README.md | 45 ++++++++++++++------ src/lib/tabs/tab-content.ts | 12 ------ src/lib/tabs/tab-group.html | 9 +++- src/lib/tabs/tab-group.spec.ts | 73 +++++++++++++++++++++++++++----- src/lib/tabs/tab.html | 4 ++ src/lib/tabs/tabs.ts | 58 +++++++++++++++++-------- 8 files changed, 174 insertions(+), 74 deletions(-) delete mode 100644 src/lib/tabs/tab-content.ts create mode 100644 src/lib/tabs/tab.html diff --git a/src/demo-app/tabs/tabs-demo.html b/src/demo-app/tabs/tabs-demo.html index 656b09d02a71..99d73d9ec327 100644 --- a/src/demo-app/tabs/tabs-demo.html +++ b/src/demo-app/tabs/tabs-demo.html @@ -19,13 +19,11 @@

Tab Group Demo

- + {{tab.content}} +
+
+
+
@@ -35,12 +33,21 @@

Async Tabs

- + {{tab.content}} +
+
+
+ +
+
+ + +

Tabs with simplified api

+ + + This tab is about the Earth! + + + This tab is about combustion! diff --git a/src/demo-app/tabs/tabs-demo.ts b/src/demo-app/tabs/tabs-demo.ts index 45c7421da466..da9988ddd371 100644 --- a/src/demo-app/tabs/tabs-demo.ts +++ b/src/demo-app/tabs/tabs-demo.ts @@ -11,16 +11,16 @@ import {Observable} from 'rxjs/Observable'; }) export class TabsDemo { tabLinks = [ - { label: 'Sun', link: 'sunny-tab'}, - { label: 'Rain', link: 'rainy-tab'}, - { label: 'Fog', link: 'foggy-tab'}, + {label: 'Sun', link: 'sunny-tab'}, + {label: 'Rain', link: 'rainy-tab'}, + {label: 'Fog', link: 'foggy-tab'}, ]; activeLinkIndex = 0; tabs = [ - { label: 'Tab One', content: 'This is the body of the first tab' }, - { label: 'Tab Two', content: 'This is the body of the second tab' }, - { label: 'Tab Three', content: 'This is the body of the third tab' }, + {label: 'Tab One', content: 'This is the body of the first tab'}, + {label: 'Tab Two', content: 'This is the body of the second tab'}, + {label: 'Tab Three', content: 'This is the body of the third tab'}, ]; asyncTabs: Observable; diff --git a/src/lib/tabs/README.md b/src/lib/tabs/README.md index 8e6a763baf13..f7eec538dfdb 100644 --- a/src/lib/tabs/README.md +++ b/src/lib/tabs/README.md @@ -15,28 +15,22 @@ Tab groups allow the user to organize their content by labels such that only one | `focusChange` | `Event` | Fired when focus changes from one label to another | | `selectChange` | `Event` | Fired when the selected tab changes | -### Examples +### Basic use A basic tab group would have the following markup. ```html - - - + +

Some tab content

+

...

- - - + +

Some more tab content

+

...

``` -It is also possible to specifiy the active tab by using the `selectedIndex` property. +You can specifiy the active tab by using the `selectedIndex` property. ```html @@ -45,3 +39,26 @@ It is also possible to specifiy the active tab by using the `selectedIndex` prop ``` **Note**: The index always starts counting from `zero`. + + +### Tabs with label templates +If you want to use an arbitrary template for your tab, you can use the `md-tab-label` directive to +provide the label template: +```html + + + +

Best pasta restaurants

+

...

+
+ + +

Terrible sushi restaurants

+

...

+
+
+``` diff --git a/src/lib/tabs/tab-content.ts b/src/lib/tabs/tab-content.ts deleted file mode 100644 index 9ea780e3d3b2..000000000000 --- a/src/lib/tabs/tab-content.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {Directive, TemplateRef, ViewContainerRef} from '@angular/core'; -import {TemplatePortalDirective} from '../core'; - -/** Used to flag tab contents for use with the portal directive */ -@Directive({ - selector: '[md-tab-content]' -}) -export class MdTabContent extends TemplatePortalDirective { - constructor(templateRef: TemplateRef, viewContainerRef: ViewContainerRef) { - super(templateRef, viewContainerRef); - } -} diff --git a/src/lib/tabs/tab-group.html b/src/lib/tabs/tab-group.html index 425d7327b327..6acbed0769f4 100644 --- a/src/lib/tabs/tab-group.html +++ b/src/lib/tabs/tab-group.html @@ -9,7 +9,14 @@ [class.md-tab-active]="selectedIndex == i" [class.md-tab-disabled]="tab.disabled" (click)="focusIndex = selectedIndex = i"> - + + + + + + diff --git a/src/lib/tabs/tab-group.spec.ts b/src/lib/tabs/tab-group.spec.ts index 5cdca64ae622..d6dd7a9f47f1 100644 --- a/src/lib/tabs/tab-group.spec.ts +++ b/src/lib/tabs/tab-group.spec.ts @@ -13,7 +13,8 @@ describe('MdTabGroup', () => { declarations: [ SimpleTabsTestApp, AsyncTabsTestApp, - DisabledTabsTestApp + DisabledTabsTestApp, + TabGroupWithSimpleApi, ], }); @@ -241,6 +242,37 @@ describe('MdTabGroup', () => { })); }); + describe('with simple api', () => { + let fixture: ComponentFixture; + let tabGroup: MdTabGroup; + + beforeEach(() => { + fixture = TestBed.createComponent(TabGroupWithSimpleApi); + fixture.detectChanges(); + + tabGroup = + fixture.debugElement.query(By.directive(MdTabGroup)).componentInstance as MdTabGroup; + }); + + it('should support a tab-group with the simple api', () => { + expect(getSelectedLabel(fixture).textContent).toMatch('Junk food'); + expect(getSelectedContent(fixture).textContent).toMatch('Pizza, fries'); + + tabGroup.selectedIndex = 2; + fixture.detectChanges(); + + expect(getSelectedLabel(fixture).textContent).toMatch('Fruit'); + expect(getSelectedContent(fixture).textContent).toMatch('Apples, grapes'); + + fixture.componentInstance.otherLabel = 'Chips'; + fixture.componentInstance.otherContent = 'Salt, vinegar'; + fixture.detectChanges(); + + expect(getSelectedLabel(fixture).textContent).toMatch('Chips'); + expect(getSelectedContent(fixture).textContent).toMatch('Salt, vinegar'); + }); + }); + /** * Checks that the `selectedIndex` has been updated; checks that the label and body have the * `md-tab-active` class @@ -260,10 +292,17 @@ describe('MdTabGroup', () => { .query(By.css(`#${tabLabelElement.id}`)).nativeElement; expect(tabContentElement.classList.contains('md-tab-active')).toBe(true); } + + function getSelectedLabel(fixture: ComponentFixture): HTMLElement { + return fixture.nativeElement.querySelector('.md-tab-label.md-tab-active'); + } + + function getSelectedContent(fixture: ComponentFixture): HTMLElement { + return fixture.nativeElement.querySelector('.md-tab-body.md-tab-active'); + } }); @Component({ - selector: 'test-app', template: ` { (selectChange)="handleSelection($event)"> - + Tab one content - + Tab two content - + Tab three content ` @@ -302,15 +341,15 @@ class SimpleTabsTestApp { - + Tab one content - + Tab two content - + Tab three content `, @@ -318,12 +357,11 @@ class SimpleTabsTestApp { class DisabledTabsTestApp {} @Component({ - selector: 'test-app', template: ` - + {{ tab.content }} ` @@ -343,3 +381,18 @@ class AsyncTabsTestApp { }); } } + + +@Component({ + template: ` + + Pizza, fries + Broccoli, spinach + {{otherContent}} + + ` +}) +class TabGroupWithSimpleApi { + otherLabel = 'Fruit'; + otherContent = 'Apples, grapes'; +} diff --git a/src/lib/tabs/tab.html b/src/lib/tabs/tab.html new file mode 100644 index 000000000000..d3c3a8152654 --- /dev/null +++ b/src/lib/tabs/tab.html @@ -0,0 +1,4 @@ + + diff --git a/src/lib/tabs/tabs.ts b/src/lib/tabs/tabs.ts index ed4843dbd867..8c88f1cc1d78 100644 --- a/src/lib/tabs/tabs.ts +++ b/src/lib/tabs/tabs.ts @@ -2,7 +2,7 @@ import { NgModule, ModuleWithProviders, ContentChild, - Directive, + ViewChild, Component, Input, Output, @@ -10,12 +10,21 @@ import { NgZone, EventEmitter, QueryList, - ContentChildren + ContentChildren, + TemplateRef, + ViewContainerRef, + OnInit, } from '@angular/core'; import {CommonModule} from '@angular/common'; -import {PortalModule, RIGHT_ARROW, LEFT_ARROW, ENTER, coerceBooleanProperty} from '../core'; +import { + PortalModule, + TemplatePortal, + RIGHT_ARROW, + LEFT_ARROW, + ENTER, + coerceBooleanProperty, +} from '../core'; import {MdTabLabel} from './tab-label'; -import {MdTabContent} from './tab-content'; import {MdTabLabelWrapper} from './tab-label-wrapper'; import {MdTabNavBar, MdTabLink} from './tab-nav-bar/tab-nav-bar'; import {MdInkBar} from './ink-bar'; @@ -32,20 +41,35 @@ export class MdTabChangeEvent { tab: MdTab; } -@Directive({ - selector: 'md-tab' +@Component({ + moduleId: module.id, + selector: 'md-tab', + templateUrl: 'tab.html', }) -export class MdTab { - @ContentChild(MdTabLabel) label: MdTabLabel; - @ContentChild(MdTabContent) content: MdTabContent; +export class MdTab implements OnInit { + /** Content for the tab label given by