Skip to content

Commit d77e49f

Browse files
committed
fix dynamic height on new tabs
1 parent 8a6c0c8 commit d77e49f

File tree

8 files changed

+227
-209
lines changed

8 files changed

+227
-209
lines changed

src/demo-app/tabs/tabs-demo.html

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ <h1>Tab Group Demo - Dynamic Tabs</h1>
4040
Selected tab index:
4141
<md-input type="number" [(ngModel)]="activeTabIndex"></md-input>
4242
</div>
43-
4443
<md-tab-group class="demo-tab-group"
4544
md-dynamic-height
4645
[(selectedIndex)]="activeTabIndex">
@@ -80,11 +79,14 @@ <h1>Tab Group Demo - Dynamic Tabs</h1>
8079
<br>
8180
<md-input placeholder="Tab Label" [(ngModel)]="tab.label"></md-input>
8281
<br><br>
83-
<button md-raised-button (click)="deleteTab(tab)">Delete Tab</button>
82+
<button md-raised-button
83+
[disabled]="dynamicTabs.length == 1"
84+
(click)="deleteTab(tab)">
85+
Delete Tab
86+
</button>
8487
</md-tab>
8588
</md-tab-group>
8689

87-
8890
<h1>Tab Group Demo - Dynamic Height</h1>
8991

9092
<md-tab-group class="demo-tab-group" md-dynamic-height>
@@ -191,4 +193,4 @@ <h1>Tabs with simplified api</h1>
191193
<md-tab label="Fire">
192194
This tab is about combustion!
193195
</md-tab>
194-
</md-tab-group>
196+
</md-tab-group>

src/demo-app/tabs/tabs-demo.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,8 @@ export class TabsDemo {
3636
content: 'This is the body of the fourth tab'
3737
},
3838
];
39-
39+
4040
// Dynamic tabs demo
41-
selectedIndex = 0;
4241
activeTabIndex = 0;
4342
addTabPosition = 0;
4443
gotoNewTabAfterAdding = false;

src/lib/tabs/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export * from './tabs';
1+
export * from './tab-group';

src/lib/tabs/tab-body.ts

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import {
2+
ViewChild,
3+
Component,
4+
Input,
5+
Output,
6+
EventEmitter,
7+
OnInit,
8+
trigger,
9+
state,
10+
style,
11+
animate,
12+
transition,
13+
AnimationTransitionEvent,
14+
ElementRef,
15+
Optional
16+
} from '@angular/core';
17+
import {TemplatePortal, PortalHostDirective, Dir, LayoutDirection} from '../core';
18+
import 'rxjs/add/operator/map';
19+
20+
export type MdTabBodyPositionState =
21+
'left' | 'center' | 'right' | 'left-origin-center' | 'right-origin-center';
22+
23+
export type MdTabBodyOriginState = 'left' | 'right';
24+
25+
@Component({
26+
moduleId: module.id,
27+
selector: 'md-tab-body',
28+
templateUrl: 'tab-body.html',
29+
animations: [
30+
trigger('translateTab', [
31+
state('left', style({transform: 'translate3d(-100%, 0, 0)'})),
32+
state('left-origin-center', style({transform: 'translate3d(0, 0, 0)'})),
33+
state('right-origin-center', style({transform: 'translate3d(0, 0, 0)'})),
34+
state('center', style({transform: 'translate3d(0, 0, 0)'})),
35+
state('right', style({transform: 'translate3d(100%, 0, 0)'})),
36+
transition('* => left, * => right, left => center, right => center',
37+
animate('500ms cubic-bezier(0.35, 0, 0.25, 1)')),
38+
transition('void => left-origin-center', [
39+
style({transform: 'translate3d(-100%, 0, 0)'}),
40+
animate('500ms cubic-bezier(0.35, 0, 0.25, 1)')
41+
]),
42+
transition('void => right-origin-center', [
43+
style({transform: 'translate3d(100%, 0, 0)'}),
44+
animate('500ms cubic-bezier(0.35, 0, 0.25, 1)')
45+
])
46+
])
47+
],
48+
host: {
49+
'md-tab-body-active': "'this._position == 'center'"
50+
}
51+
})
52+
export class MdTabBody implements OnInit {
53+
/** The portal host inside of this container into which the tab body content will be loaded. */
54+
@ViewChild(PortalHostDirective) _portalHost: PortalHostDirective;
55+
56+
/** Event emitted when the tab begins to animate towards the center as the active tab. */
57+
@Output()
58+
onTabBodyCentering: EventEmitter<number> = new EventEmitter<number>();
59+
60+
/** Event emitted when the tab completes its animation towards the center. */
61+
@Output()
62+
onTabBodyCentered: EventEmitter<void> = new EventEmitter<void>(true);
63+
64+
/** The tab body content to display. */
65+
@Input('md-tab-body-content') _content: TemplatePortal;
66+
67+
/** The shifted index position of the tab body, where zero represents the active center tab. */
68+
_position: MdTabBodyPositionState;
69+
@Input('md-tab-position') set position(position: number) {
70+
if (position < 0) {
71+
this._position = this._getLayoutDirection() == 'ltr' ? 'left' : 'right';
72+
} else if (position > 0) {
73+
this._position = this._getLayoutDirection() == 'ltr' ? 'right' : 'left';
74+
} else {
75+
this._position = 'center';
76+
}
77+
}
78+
79+
/** The origin position from which this tab should appear when it is centered into view. */
80+
_origin: MdTabBodyOriginState;
81+
@Input('md-tab-origin') set origin(origin: number) {
82+
if (origin == null) { return; }
83+
84+
if (origin <= 0) {
85+
this._origin = this._getLayoutDirection() == 'ltr' ? 'left' : 'right';
86+
} else {
87+
this._origin = this._getLayoutDirection() == 'ltr' ? 'right' : 'left';
88+
}
89+
}
90+
91+
constructor(private _elementRef: ElementRef, @Optional() private _dir: Dir) {}
92+
93+
/**
94+
* After initialized, check if the content is centered and has an origin. If so, set the
95+
* special position states that transition the tab from the left or right before centering.
96+
*/
97+
ngOnInit() {
98+
if (this._position == 'center' && this._origin) {
99+
this._position = this._origin == 'left' ? 'left-origin-center' : 'right-origin-center';
100+
}
101+
}
102+
103+
/**
104+
* After the view has been set, check if the tab content is set to the center and attach the
105+
* content if it is not already attached.
106+
*/
107+
ngAfterViewChecked() {
108+
if (this._isCenterPosition(this._position) && !this._portalHost.hasAttached()) {
109+
this._portalHost.attach(this._content);
110+
}
111+
}
112+
113+
_onTranslateTabStarted(e: AnimationTransitionEvent) {
114+
console.log('Animation began with position ', this._position);
115+
if (this._isCenterPosition(e.toState)) {
116+
this.onTabBodyCentering.emit(this._elementRef.nativeElement.clientHeight);
117+
}
118+
}
119+
120+
_onTranslateTabComplete(e: AnimationTransitionEvent) {
121+
// If the end state is that the tab is not centered, then detach the content.
122+
if (!this._isCenterPosition(e.toState) && !this._isCenterPosition(this._position)) {
123+
this._portalHost.detach();
124+
}
125+
126+
// If the transition to the center is complete, emit an event.
127+
if (this._isCenterPosition(e.toState) && this._isCenterPosition(this._position)) {
128+
this.onTabBodyCentered.emit();
129+
}
130+
}
131+
132+
/** The text direction of the containing app. */
133+
_getLayoutDirection(): LayoutDirection {
134+
return this._dir && this._dir.value === 'rtl' ? 'rtl' : 'ltr';
135+
}
136+
137+
138+
/** Whether the provided position state is considered center, regardless of origin. */
139+
private _isCenterPosition(position: MdTabBodyPositionState|string): boolean {
140+
return position == 'center' ||
141+
position == 'left-origin-center' ||
142+
position == 'right-origin-center';
143+
}
144+
}

src/lib/tabs/tab-group.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {
22
async, fakeAsync, tick, ComponentFixture, TestBed,
33
flushMicrotasks
44
} from '@angular/core/testing';
5-
import {MdTabGroup, MdTabsModule} from './tabs';
5+
import {MdTabGroup, MdTabsModule} from './tab-group';
66
import {Component, ViewChild} from '@angular/core';
77
import {By} from '@angular/platform-browser';
88
import {Observable} from 'rxjs/Observable';

0 commit comments

Comments
 (0)