mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(navbar): update ink bar when links change (#4897)
* fix(navbar): update ink bar when links change * remove add link * fix test * change strategy - use mutation observer * cleanup
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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', () => {
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
import {
|
||||
Component,
|
||||
Input,
|
||||
ViewChild,
|
||||
ElementRef,
|
||||
ViewEncapsulation,
|
||||
Directive,
|
||||
NgZone,
|
||||
Inject,
|
||||
Optional,
|
||||
OnDestroy,
|
||||
AfterContentInit,
|
||||
Component,
|
||||
Directive,
|
||||
ElementRef,
|
||||
Inject,
|
||||
Input,
|
||||
NgZone,
|
||||
OnDestroy,
|
||||
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.
|
||||
@@ -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;
|
||||
@@ -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());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user