diff --git a/src/lib/tabs/ink-bar.ts b/src/lib/tabs/ink-bar.ts index efeadf0b4688..ec2cacd37e8e 100644 --- a/src/lib/tabs/ink-bar.ts +++ b/src/lib/tabs/ink-bar.ts @@ -1,4 +1,4 @@ -import {Directive, Renderer, ElementRef} from '@angular/core'; +import {Directive, Renderer, ElementRef, NgZone} from '@angular/core'; /** @@ -12,7 +12,10 @@ import {Directive, Renderer, ElementRef} from '@angular/core'; }, }) export class MdInkBar { - constructor(private _renderer: Renderer, private _elementRef: ElementRef) {} + constructor( + private _renderer: Renderer, + private _elementRef: ElementRef, + private _ngZone: NgZone) {} /** * Calculates the styles from the provided element in order to align the ink-bar to that element. @@ -21,10 +24,15 @@ export class MdInkBar { */ alignToElement(element: HTMLElement) { this.show(); - this._renderer.setElementStyle(this._elementRef.nativeElement, 'left', - this._getLeftPosition(element)); - this._renderer.setElementStyle(this._elementRef.nativeElement, 'width', - this._getElementWidth(element)); + + this._ngZone.runOutsideAngular(() => { + requestAnimationFrame(() => { + this._renderer.setElementStyle(this._elementRef.nativeElement, 'left', + this._getLeftPosition(element)); + this._renderer.setElementStyle(this._elementRef.nativeElement, 'width', + this._getElementWidth(element)); + }); + }); } /** Shows the ink bar. */ diff --git a/src/lib/tabs/tab-header.spec.ts b/src/lib/tabs/tab-header.spec.ts index 3c3e068bd06e..89d931d4c108 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}, ] }); @@ -192,8 +196,22 @@ describe('MdTabHeader', () => { expect(appComponent.mdTabHeader.scrollDistance).toBe(0); }); }); - }); + it('should re-align the ink bar when the direction changes', () => { + fixture = TestBed.createComponent(SimpleTabHeaderApp); + fixture.detectChanges(); + + const inkBar = fixture.componentInstance.mdTabHeader._inkBar; + + spyOn(inkBar, 'alignToElement'); + + dirChange.next(); + fixture.detectChanges(); + + expect(inkBar.alignToElement).toHaveBeenCalled(); + }); + + }); }); interface Tab { @@ -211,7 +229,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..3fee07a9f749 100644 --- a/src/lib/tabs/tab-header.ts +++ b/src/lib/tabs/tab-header.ts @@ -2,7 +2,6 @@ import { ViewChild, Component, Input, - NgZone, QueryList, ElementRef, ViewEncapsulation, @@ -12,12 +11,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 +52,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 +68,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; @@ -102,9 +106,7 @@ export class MdTabHeader implements AfterContentChecked, AfterContentInit { /** Event emitted when a label is focused. */ @Output() indexFocused = new EventEmitter(); - constructor(private _zone: NgZone, - private _elementRef: ElementRef, - @Optional() private _dir: Dir) {} + constructor(private _elementRef: ElementRef, @Optional() private _dir: Dir) {} ngAfterContentChecked(): void { // If the number of tab labels have changed, check if scrolling should be enabled @@ -149,6 +151,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; + } } /** @@ -373,10 +386,6 @@ export class MdTabHeader implements AfterContentChecked, AfterContentInit { ? this._labelWrappers.toArray()[this.selectedIndex].elementRef.nativeElement : null; - this._zone.runOutsideAngular(() => { - requestAnimationFrame(() => { - this._inkBar.alignToElement(selectedLabelWrapper); - }); - }); + this._inkBar.alignToElement(selectedLabelWrapper); } } 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..6bc6d6dec836 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) { + 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,22 @@ 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._inkBar.alignToElement(this._activeLinkElement.nativeElement); + } } /**