diff --git a/src/material-experimental/mdc-tabs/ink-bar.ts b/src/material-experimental/mdc-tabs/ink-bar.ts index d3944be0f6a2..9835e498d319 100644 --- a/src/material-experimental/mdc-tabs/ink-bar.ts +++ b/src/material-experimental/mdc-tabs/ink-bar.ts @@ -80,7 +80,9 @@ export class MatInkBarFoundation { } }, setContentStyleProperty: (propName, value) => { - this._inkBarContentElement.style.setProperty(propName, value); + if (!this._destroyed) { + this._inkBarContentElement.style.setProperty(propName, value); + } }, computeContentClientRect: () => { // `getBoundingClientRect` isn't available on the server. diff --git a/src/material-experimental/mdc-tabs/tab-header.spec.ts b/src/material-experimental/mdc-tabs/tab-header.spec.ts index 5922f5c8c679..8001b7f9a4c5 100644 --- a/src/material-experimental/mdc-tabs/tab-header.spec.ts +++ b/src/material-experimental/mdc-tabs/tab-header.spec.ts @@ -1,4 +1,4 @@ -import {Direction, Directionality} from '@angular/cdk/bidi'; +import {Direction} from '@angular/cdk/bidi'; import {END, ENTER, HOME, LEFT_ARROW, RIGHT_ARROW, SPACE} from '@angular/cdk/keycodes'; import {PortalModule} from '@angular/cdk/portal'; import {ScrollingModule, ViewportRuler} from '@angular/cdk/scrolling'; @@ -23,25 +23,18 @@ import {MatRippleModule} from '@angular/material-experimental/mdc-core'; import {By} from '@angular/platform-browser'; import {MatTabHeader} from './tab-header'; import {MatTabLabelWrapper} from './tab-label-wrapper'; -import {Subject} from 'rxjs'; import {ObserversModule, MutationObserverFactory} from '@angular/cdk/observers'; describe('MDC-based MatTabHeader', () => { - let dir: Direction = 'ltr'; - let change = new Subject(); let fixture: ComponentFixture; let appComponent: SimpleTabHeaderApp; beforeEach( waitForAsync(() => { - dir = 'ltr'; TestBed.configureTestingModule({ imports: [CommonModule, PortalModule, MatRippleModule, ScrollingModule, ObserversModule], declarations: [MatTabHeader, MatTabLabelWrapper, SimpleTabHeaderApp], - providers: [ - ViewportRuler, - {provide: Directionality, useFactory: () => ({value: dir, change: change})}, - ], + providers: [ViewportRuler], }); TestBed.compileComponents(); @@ -238,11 +231,10 @@ describe('MDC-based MatTabHeader', () => { describe('pagination', () => { describe('ltr', () => { beforeEach(() => { - dir = 'ltr'; fixture = TestBed.createComponent(SimpleTabHeaderApp); - fixture.detectChanges(); - appComponent = fixture.componentInstance; + appComponent.dir = 'ltr'; + fixture.detectChanges(); }); it('should show width when tab list width exceeds container', () => { @@ -322,11 +314,9 @@ describe('MDC-based MatTabHeader', () => { describe('rtl', () => { beforeEach(() => { - dir = 'rtl'; fixture = TestBed.createComponent(SimpleTabHeaderApp); appComponent = fixture.componentInstance; appComponent.dir = 'rtl'; - fixture.detectChanges(); }); @@ -607,9 +597,9 @@ describe('MDC-based MatTabHeader', () => { fixture.detectChanges(); - change.next(); + fixture.componentInstance.dir = 'rtl'; fixture.detectChanges(); - tick(20); // Angular turns rAF calls into 16.6ms timeouts in tests. + tick(); expect(inkBar.alignToElement).toHaveBeenCalled(); })); diff --git a/src/material/tabs/ink-bar.ts b/src/material/tabs/ink-bar.ts index 5291553b1b96..84e7d3c1f7ea 100644 --- a/src/material/tabs/ink-bar.ts +++ b/src/material/tabs/ink-bar.ts @@ -8,6 +8,7 @@ import {Directive, ElementRef, Inject, InjectionToken, NgZone, Optional} from '@angular/core'; import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; +import {take} from 'rxjs/operators'; /** * Interface for a a MatInkBar positioner method, defining the positioning and width of the ink @@ -65,14 +66,12 @@ export class MatInkBar { */ alignToElement(element: HTMLElement) { this.show(); - - if (typeof requestAnimationFrame !== 'undefined') { - this._ngZone.runOutsideAngular(() => { - requestAnimationFrame(() => this._setStyles(element)); - }); - } else { - this._setStyles(element); - } + this._ngZone.onStable.pipe(take(1)).subscribe(() => { + const positions = this._inkBarPositioner(element); + const inkBar: HTMLElement = this._elementRef.nativeElement; + inkBar.style.left = positions.left; + inkBar.style.width = positions.width; + }); } /** Shows the ink bar. */ @@ -84,16 +83,4 @@ export class MatInkBar { hide(): void { this._elementRef.nativeElement.style.visibility = 'hidden'; } - - /** - * Sets the proper styles to the ink bar element. - * @param element - */ - private _setStyles(element: HTMLElement) { - const positions = this._inkBarPositioner(element); - const inkBar: HTMLElement = this._elementRef.nativeElement; - - inkBar.style.left = positions.left; - inkBar.style.width = positions.width; - } } diff --git a/src/material/tabs/paginated-tab-header.ts b/src/material/tabs/paginated-tab-header.ts index 6ea78907b278..6c67bcee839e 100644 --- a/src/material/tabs/paginated-tab-header.ts +++ b/src/material/tabs/paginated-tab-header.ts @@ -32,7 +32,7 @@ import {ViewportRuler} from '@angular/cdk/scrolling'; import {FocusKeyManager, FocusableOption} from '@angular/cdk/a11y'; import {ENTER, SPACE, hasModifierKey} from '@angular/cdk/keycodes'; import {merge, of as observableOf, Subject, timer, fromEvent} from 'rxjs'; -import {takeUntil} from 'rxjs/operators'; +import {take, takeUntil} from 'rxjs/operators'; import {Platform, normalizePassiveListenerOptions} from '@angular/cdk/platform'; import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; @@ -212,7 +212,9 @@ export abstract class MatPaginatedTabHeader // Defer the first call in order to allow for slower browsers to lay out the elements. // This helps in cases where the user lands directly on a page with paginated tabs. - typeof requestAnimationFrame !== 'undefined' ? requestAnimationFrame(realign) : realign(); + // Note that we use `onStable` instead of `requestAnimationFrame`, because the latter + // can hold up tests that are in a background tab. + this._ngZone.onStable.pipe(take(1)).subscribe(realign); // On dir change or window resize, realign the ink bar and update the orientation of // the key manager if the direction has changed. diff --git a/src/material/tabs/tab-header.spec.ts b/src/material/tabs/tab-header.spec.ts index 41749fd0adee..93c10048710f 100644 --- a/src/material/tabs/tab-header.spec.ts +++ b/src/material/tabs/tab-header.spec.ts @@ -1,4 +1,4 @@ -import {Direction, Directionality} from '@angular/cdk/bidi'; +import {Direction} from '@angular/cdk/bidi'; import {END, ENTER, HOME, LEFT_ARROW, RIGHT_ARROW, SPACE} from '@angular/cdk/keycodes'; import {PortalModule} from '@angular/cdk/portal'; import {ScrollingModule, ViewportRuler} from '@angular/cdk/scrolling'; @@ -24,25 +24,18 @@ import {By} from '@angular/platform-browser'; import {MatInkBar} from './ink-bar'; import {MatTabHeader} from './tab-header'; import {MatTabLabelWrapper} from './tab-label-wrapper'; -import {Subject} from 'rxjs'; import {ObserversModule, MutationObserverFactory} from '@angular/cdk/observers'; describe('MatTabHeader', () => { - let dir: Direction = 'ltr'; - let change = new Subject(); let fixture: ComponentFixture; let appComponent: SimpleTabHeaderApp; beforeEach( waitForAsync(() => { - dir = 'ltr'; TestBed.configureTestingModule({ imports: [CommonModule, PortalModule, MatRippleModule, ScrollingModule, ObserversModule], declarations: [MatTabHeader, MatInkBar, MatTabLabelWrapper, SimpleTabHeaderApp], - providers: [ - ViewportRuler, - {provide: Directionality, useFactory: () => ({value: dir, change: change})}, - ], + providers: [ViewportRuler], }); TestBed.compileComponents(); @@ -239,11 +232,10 @@ describe('MatTabHeader', () => { describe('pagination', () => { describe('ltr', () => { beforeEach(() => { - dir = 'ltr'; fixture = TestBed.createComponent(SimpleTabHeaderApp); - fixture.detectChanges(); - appComponent = fixture.componentInstance; + appComponent.dir = 'ltr'; + fixture.detectChanges(); }); it('should show width when tab list width exceeds container', () => { @@ -319,11 +311,9 @@ describe('MatTabHeader', () => { describe('rtl', () => { beforeEach(() => { - dir = 'rtl'; fixture = TestBed.createComponent(SimpleTabHeaderApp); appComponent = fixture.componentInstance; appComponent.dir = 'rtl'; - fixture.detectChanges(); }); @@ -603,9 +593,9 @@ describe('MatTabHeader', () => { fixture.detectChanges(); - change.next(); + fixture.componentInstance.dir = 'rtl'; fixture.detectChanges(); - tick(20); // Angular turns rAF calls into 16.6ms timeouts in tests. + tick(); expect(inkBar.alignToElement).toHaveBeenCalled(); }));