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.label}}
-
- {{tab.content}}
-
-
-
-
-
+ {{tab.content}}
+
+
+
+
@@ -35,12 +33,21 @@ Async Tabs
{{tab.label}}
-
- {{tab.content}}
-
-
-
-
-
+ {{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
-
- One
-
- Some tab content
- ...
-
+
+ Some tab content
+ ...
-
- Two
-
- Some more 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
+
+
+
+ The best pasta
+
+ Best pasta restaurants
+ ...
+
+
+
+ thumb_down The worst sushi
+
+ 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">
-
+
+
+
+
+
+
+
+ {{tab.textLabel}}
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
- Tab one content
+ Tab one content
Tab Two
- Tab two content
+ Tab two content
Tab Three
- Tab three content
+ Tab three content
`
@@ -302,15 +341,15 @@ class SimpleTabsTestApp {
Tab One
- Tab one content
+ Tab one content
Tab Two
- Tab two content
+ Tab two content
Tab Three
- Tab three content
+ Tab three content
`,
@@ -318,12 +357,11 @@ class SimpleTabsTestApp {
class DisabledTabsTestApp {}
@Component({
- selector: 'test-app',
template: `
{{ tab.label }}
- {{ tab.content }}
+ {{ 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 . */
+ @ContentChild(MdTabLabel) templateLabel: MdTabLabel;
- private _disabled = false;
- @Input('disabled')
- set disabled(value: boolean) {
- this._disabled = coerceBooleanProperty(value);
+ /** Template inside the MdTab view that contains an . */
+ @ViewChild(TemplateRef) _content: TemplateRef;
+
+ /** The plain text label for the tab, used when there is no template label. */
+ @Input('label') textLabel: string = '';
+
+ private _contentPortal: TemplatePortal = null;
+
+ constructor(private _viewContainerRef: ViewContainerRef) { }
+
+ ngOnInit() {
+ this._contentPortal = new TemplatePortal(this._content, this._viewContainerRef);
}
- get disabled(): boolean {
- return this._disabled;
+
+ private _disabled = false;
+ @Input() set disabled(value: boolean) { this._disabled = coerceBooleanProperty(value); }
+ get disabled(): boolean { return this._disabled; }
+
+ get content(): TemplatePortal {
+ return this._contentPortal;
}
}
@@ -230,8 +254,8 @@ export class MdTabGroup {
@NgModule({
imports: [CommonModule, PortalModule],
// Don't export MdInkBar or MdTabLabelWrapper, as they are internal implementation details.
- exports: [MdTabGroup, MdTabLabel, MdTabContent, MdTab, MdTabNavBar, MdTabLink],
- declarations: [MdTabGroup, MdTabLabel, MdTabContent, MdTab, MdInkBar, MdTabLabelWrapper,
+ exports: [MdTabGroup, MdTabLabel, MdTab, MdTabNavBar, MdTabLink],
+ declarations: [MdTabGroup, MdTabLabel, MdTab, MdInkBar, MdTabLabelWrapper,
MdTabNavBar, MdTabLink],
})
export class MdTabsModule {