Skip to content

Commit

Permalink
fix(navbar): update ink bar when links change (#4897)
Browse files Browse the repository at this point in the history
* fix(navbar): update ink bar when links change

* remove add link

* fix test

* change strategy - use mutation observer

* cleanup
  • Loading branch information
andrewseguin authored Jun 5, 2017
1 parent 2e3910c commit 41c43cc
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 29 deletions.
4 changes: 4 additions & 0 deletions src/demo-app/tabs/tabs-demo.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<h1>Tab Nav Bar</h1>

<button md-button (click)="tabLinks.shift()">Remove tab</button>
<button md-button (click)="swapTabLinks()">Swap first two</button>
<button md-button (click)="addToLabel()">Add to labels</button>

<div class="demo-nav-bar">
<nav md-tab-nav-bar aria-label="weather navigation links">
<a md-tab-link
Expand Down
10 changes: 10 additions & 0 deletions src/demo-app/tabs/tabs-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,16 @@ export class TabsDemo {
deleteTab(tab: any) {
this.dynamicTabs.splice(this.dynamicTabs.indexOf(tab), 1);
}

swapTabLinks() {
const temp = this.tabLinks[0];
this.tabLinks[0] = this.tabLinks[1];
this.tabLinks[1] = temp;
}

addToLabel() {
this.tabLinks.forEach(link => link.label += 'extracontent');
}
}


Expand Down
2 changes: 1 addition & 1 deletion src/lib/tabs/tab-nav-bar/tab-nav-bar.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="mat-tab-links">
<div class="mat-tab-links" (cdkObserveContent)="_alignInkBar()">
<ng-content></ng-content>
<md-ink-bar></md-ink-bar>
</div>
Expand Down
50 changes: 40 additions & 10 deletions src/lib/tabs/tab-nav-bar/tab-nav-bar.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {async, ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing';
import {async, ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
import {MdTabsModule} from '../index';
import {MdTabNavBar} from './tab-nav-bar';
import {Component, ViewChild} from '@angular/core';
import {By} from '@angular/platform-browser';
import {ViewportRuler} from '../../core/overlay/position/viewport-ruler';
import {FakeViewportRuler} from '../../core/overlay/position/fake-viewport-ruler';
import {dispatchMouseEvent, dispatchFakeEvent} from '../../core/testing/dispatch-events';
import {LayoutDirection, Dir} from '../../core/rtl/dir';
import {dispatchFakeEvent, dispatchMouseEvent} from '../../core/testing/dispatch-events';
import {Dir, LayoutDirection} from '../../core/rtl/dir';
import {Subject} from 'rxjs/Subject';


Expand Down Expand Up @@ -37,20 +37,19 @@ describe('MdTabNavBar', () => {

beforeEach(() => {
fixture = TestBed.createComponent(SimpleTabNavBarTestApp);
fixture.detectChanges();
});

it('should change active index on click', () => {
let component = fixture.debugElement.componentInstance;

// select the second link
let tabLink = fixture.debugElement.queryAll(By.css('a'))[1];
tabLink.nativeElement.click();
expect(component.activeIndex).toBe(1);
expect(fixture.componentInstance.activeIndex).toBe(1);

// select the third link
tabLink = fixture.debugElement.queryAll(By.css('a'))[2];
tabLink.nativeElement.click();
expect(component.activeIndex).toBe(2);
expect(fixture.componentInstance.activeIndex).toBe(2);
});

it('should re-align the ink bar when the direction changes', () => {
Expand All @@ -64,6 +63,31 @@ describe('MdTabNavBar', () => {
expect(inkBar.alignToElement).toHaveBeenCalled();
});

it('should re-align the ink bar when the tabs list change', () => {
const inkBar = fixture.componentInstance.tabNavBar._inkBar;

spyOn(inkBar, 'alignToElement');

fixture.componentInstance.tabs = [1, 2, 3, 4];
fixture.detectChanges();

expect(inkBar.alignToElement).toHaveBeenCalled();
});

it('should re-align the ink bar when the tab labels change the width', done => {
const inkBar = fixture.componentInstance.tabNavBar._inkBar;

const spy = spyOn(inkBar, 'alignToElement').and.callFake(() => {
expect(spy.calls.any()).toBe(true);
done();
});

fixture.componentInstance.label = 'label change';
fixture.detectChanges();

expect(spy.calls.any()).toBe(false);
});

it('should re-align the ink bar when the window is resized', fakeAsync(() => {
const inkBar = fixture.componentInstance.tabNavBar._inkBar;

Expand Down Expand Up @@ -97,15 +121,21 @@ describe('MdTabNavBar', () => {
selector: 'test-app',
template: `
<nav md-tab-nav-bar>
<a md-tab-link [active]="activeIndex === 0" (click)="activeIndex = 0">Tab One</a>
<a md-tab-link [active]="activeIndex === 1" (click)="activeIndex = 1">Tab Two</a>
<a md-tab-link [active]="activeIndex === 2" (click)="activeIndex = 2">Tab Three</a>
<a md-tab-link
*ngFor="let tab of tabs; let index = index"
[active]="activeIndex === index"
(click)="activeIndex = index">
Tab link {{label}}
</a>
</nav>
`
})
class SimpleTabNavBarTestApp {
@ViewChild(MdTabNavBar) tabNavBar: MdTabNavBar;

label = '';
tabs = [0, 1, 2];

activeIndex = 0;
}

Expand Down
36 changes: 18 additions & 18 deletions src/lib/tabs/tab-nav-bar/tab-nav-bar.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
import {
AfterContentInit,
Component,
Input,
ViewChild,
ElementRef,
ViewEncapsulation,
Directive,
NgZone,
ElementRef,
Inject,
Optional,
Input,
NgZone,
OnDestroy,
AfterContentInit,
Optional,
ViewChild,
ViewEncapsulation
} 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, Dir, Platform} from '../../core';
import {Dir, MD_RIPPLE_GLOBAL_OPTIONS, Platform, RippleGlobalOptions} from '../../core';
import {Observable} from 'rxjs/Observable';
import {Subscription} from 'rxjs/Subscription';
import 'rxjs/add/operator/auditTime';
import 'rxjs/add/operator/takeUntil';
import 'rxjs/add/observable/of';
import 'rxjs/add/observable/merge';
import {Subject} from 'rxjs/Subject';

/**
* Navigation component matching the styles of the tab group header.
Expand All @@ -34,8 +35,8 @@ import 'rxjs/add/observable/merge';
encapsulation: ViewEncapsulation.None,
})
export class MdTabNavBar implements AfterContentInit, OnDestroy {
/** Combines listeners that will re-align the ink bar whenever they're invoked. */
private _realignInkBar: Subscription = null;
/** Subject that emits when the component has been destroyed. */
private _onDestroy = new Subject<void>();

_activeLinkChanged: boolean;
_activeLinkElement: ElementRef;
Expand All @@ -51,13 +52,15 @@ export class MdTabNavBar implements AfterContentInit, OnDestroy {
}

ngAfterContentInit(): void {
this._realignInkBar = this._ngZone.runOutsideAngular(() => {
this._ngZone.runOutsideAngular(() => {
let dirChange = this._dir ? this._dir.dirChange : Observable.of(null);
let resize = typeof window !== 'undefined' ?
Observable.fromEvent(window, 'resize').auditTime(10) :
Observable.of(null);

return Observable.merge(dirChange, resize).subscribe(() => this._alignInkBar());
return Observable.merge(dirChange, resize)
.takeUntil(this._onDestroy)
.subscribe(() => this._alignInkBar());
});
}

Expand All @@ -70,14 +73,11 @@ export class MdTabNavBar implements AfterContentInit, OnDestroy {
}

ngOnDestroy() {
if (this._realignInkBar) {
this._realignInkBar.unsubscribe();
this._realignInkBar = null;
}
this._onDestroy.next();
}

/** Aligns the ink bar to the active link. */
private _alignInkBar(): void {
_alignInkBar(): void {
if (this._activeLinkElement) {
this._inkBar.alignToElement(this._activeLinkElement.nativeElement);
}
Expand Down
1 change: 1 addition & 0 deletions tools/gulp/packaging/rollup-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const ROLLUP_GLOBALS = {
'rxjs/add/operator/share': 'Rx.Observable.prototype',
'rxjs/add/operator/startWith': 'Rx.Observable.prototype',
'rxjs/add/operator/switchMap': 'Rx.Observable.prototype',
'rxjs/add/operator/takeUntil': 'Rx.Observable.prototype',
'rxjs/add/operator/toPromise': 'Rx.Observable.prototype',
'rxjs/BehaviorSubject': 'Rx',
'rxjs/Observable': 'Rx',
Expand Down

0 comments on commit 41c43cc

Please sign in to comment.