diff --git a/src/lib/tabs/tab-header.spec.ts b/src/lib/tabs/tab-header.spec.ts index 3c3e068bd06e..bc87d09bbea6 100644 --- a/src/lib/tabs/tab-header.spec.ts +++ b/src/lib/tabs/tab-header.spec.ts @@ -11,10 +11,12 @@ import {RIGHT_ARROW, LEFT_ARROW, ENTER} from '../core/keyboard/keycodes'; import {FakeViewportRuler} from '../core/overlay/position/fake-viewport-ruler'; import {ViewportRuler} from '../core/overlay/position/viewport-ruler'; import {dispatchKeyboardEvent} from '../core/testing/dispatch-events'; +import {Subject} from 'rxjs/Subject'; describe('MdTabHeader', () => { let dir: LayoutDirection = 'ltr'; + let dirChange = new Subject(); let fixture: ComponentFixture; let appComponent: SimpleTabHeaderApp; @@ -29,7 +31,9 @@ describe('MdTabHeader', () => { SimpleTabHeaderApp, ], providers: [ - {provide: Dir, useFactory: () => { return {value: dir}; }}, + {provide: Dir, useFactory: () => { + return {value: dir, dirChange: dirChange.asObservable()}; + }}, {provide: ViewportRuler, useClass: FakeViewportRuler}, ] }); @@ -211,7 +215,7 @@ interface Tab { *ngFor="let tab of tabs; let i = index" [disabled]="!!tab.disabled" (click)="selectedIndex = i"> - {{tab.label}} + {{tab.label}} diff --git a/src/lib/tabs/tab-header.ts b/src/lib/tabs/tab-header.ts index 36fa3bf61dbf..a16628f66573 100644 --- a/src/lib/tabs/tab-header.ts +++ b/src/lib/tabs/tab-header.ts @@ -12,12 +12,14 @@ import { Optional, AfterContentChecked, AfterContentInit, + OnDestroy, } from '@angular/core'; import {RIGHT_ARROW, LEFT_ARROW, ENTER, Dir, LayoutDirection} from '../core'; import {MdTabLabelWrapper} from './tab-label-wrapper'; import {MdInkBar} from './ink-bar'; -import 'rxjs/add/operator/map'; +import {Subscription} from 'rxjs/Subscription'; import {applyCssTransform} from '../core/style/apply-transform'; +import 'rxjs/add/operator/map'; /** * The directions that scrolling can go in when the header's tabs exceed the header width. 'After' @@ -51,7 +53,7 @@ const EXAGGERATED_OVERSCROLL = 60; '[class.mat-tab-header-rtl]': "_getLayoutDirection() == 'rtl'", } }) -export class MdTabHeader implements AfterContentChecked, AfterContentInit { +export class MdTabHeader implements AfterContentChecked, AfterContentInit, OnDestroy { @ContentChildren(MdTabLabelWrapper) _labelWrappers: QueryList; @ViewChild(MdInkBar) _inkBar: MdInkBar; @@ -67,6 +69,9 @@ export class MdTabHeader implements AfterContentChecked, AfterContentInit { /** Whether the header should scroll to the selected index after the view has been checked. */ private _selectedIndexChanged = false; + /** Subscription to changes in the layout direction. */ + private _directionChange: Subscription; + /** Whether the controls for pagination should be displayed */ _showPaginationControls = false; @@ -149,6 +154,17 @@ export class MdTabHeader implements AfterContentChecked, AfterContentInit { */ ngAfterContentInit() { this._alignInkBarToSelectedTab(); + + if (this._dir) { + this._directionChange = this._dir.dirChange.subscribe(() => this._alignInkBarToSelectedTab()); + } + } + + ngOnDestroy() { + if (this._directionChange) { + this._directionChange.unsubscribe(); + this._directionChange = null; + } } /** diff --git a/src/lib/tabs/tab-nav-bar/tab-nav-bar.ts b/src/lib/tabs/tab-nav-bar/tab-nav-bar.ts index 0698eeed1fdd..36b788d7aad3 100644 --- a/src/lib/tabs/tab-nav-bar/tab-nav-bar.ts +++ b/src/lib/tabs/tab-nav-bar/tab-nav-bar.ts @@ -4,12 +4,17 @@ import { ViewChild, ElementRef, ViewEncapsulation, - Directive, NgZone, Inject, Optional, + Directive, + NgZone, + Inject, + Optional, + OnDestroy, } from '@angular/core'; import {MdInkBar} from '../ink-bar'; import {MdRipple} from '../../core/ripple/index'; import {ViewportRuler} from '../../core/overlay/position/viewport-ruler'; -import {MD_RIPPLE_GLOBAL_OPTIONS, RippleGlobalOptions} from '../../core/ripple/ripple'; +import {MD_RIPPLE_GLOBAL_OPTIONS, RippleGlobalOptions, Dir} from '../../core'; +import {Subscription} from 'rxjs/Subscription'; /** * Navigation component matching the styles of the tab group header. @@ -25,12 +30,19 @@ import {MD_RIPPLE_GLOBAL_OPTIONS, RippleGlobalOptions} from '../../core/ripple/r }, encapsulation: ViewEncapsulation.None, }) -export class MdTabNavBar { +export class MdTabNavBar implements OnDestroy { + private _directionChange: Subscription; _activeLinkChanged: boolean; _activeLinkElement: ElementRef; @ViewChild(MdInkBar) _inkBar: MdInkBar; + constructor(@Optional() private _dir: Dir, private _ngZone: NgZone) { + if (_dir) { + this._directionChange = _dir.dirChange.subscribe(() => this._alignInkBar()); + } + } + /** Notifies the component that the active link has been changed. */ updateActiveLink(element: ElementRef) { this._activeLinkChanged = this._activeLinkElement != element; @@ -40,10 +52,26 @@ export class MdTabNavBar { /** Checks if the active link has been changed and, if so, will update the ink bar. */ ngAfterContentChecked(): void { if (this._activeLinkChanged) { - this._inkBar.alignToElement(this._activeLinkElement.nativeElement); + this._alignInkBar(); this._activeLinkChanged = false; } } + + ngOnDestroy() { + if (this._directionChange) { + this._directionChange.unsubscribe(); + this._directionChange = null; + } + } + + /** Aligns the ink bar to the active link. */ + private _alignInkBar(): void { + this._ngZone.runOutsideAngular(() => { + requestAnimationFrame(() => { + this._inkBar.alignToElement(this._activeLinkElement.nativeElement); + }); + }); + } } /**