mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(tabs): pagination state not updated when tab content changes (#12911)
Fixes the displayed state of the tabs pagination not being updated when the content of the tabs changes. The issue comes from the fact that the content change callback runs outside the `NgZone`. Fixes #12901.
This commit is contained in:
committed by
Jeremy Elbourn
parent
0c8efa54d4
commit
a7de64a4cd
@@ -19,6 +19,7 @@ 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', () => {
|
||||
@@ -30,7 +31,7 @@ describe('MatTabHeader', () => {
|
||||
beforeEach(async(() => {
|
||||
dir = 'ltr';
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CommonModule, PortalModule, MatRippleModule, ScrollingModule],
|
||||
imports: [CommonModule, PortalModule, MatRippleModule, ScrollingModule, ObserversModule],
|
||||
declarations: [
|
||||
MatTabHeader,
|
||||
MatInkBar,
|
||||
@@ -345,6 +346,41 @@ describe('MatTabHeader', () => {
|
||||
discardPeriodicTasks();
|
||||
}));
|
||||
|
||||
it('should update the pagination state if the content of the labels changes', () => {
|
||||
const mutationCallbacks: Function[] = [];
|
||||
TestBed.overrideProvider(MutationObserverFactory, {
|
||||
useValue: {
|
||||
// Stub out the MutationObserver since the native one is async.
|
||||
create: function(callback: Function) {
|
||||
mutationCallbacks.push(callback);
|
||||
return {observe: () => {}, disconnect: () => {}};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(SimpleTabHeaderApp);
|
||||
fixture.detectChanges();
|
||||
|
||||
const tabHeaderElement: HTMLElement =
|
||||
fixture.nativeElement.querySelector('.mat-tab-header');
|
||||
const labels =
|
||||
Array.from<HTMLElement>(fixture.nativeElement.querySelectorAll('.label-content'));
|
||||
const extraText = new Array(100).fill('w').join();
|
||||
const enabledClass = 'mat-tab-header-pagination-controls-enabled';
|
||||
|
||||
expect(tabHeaderElement.classList).not.toContain(enabledClass);
|
||||
|
||||
labels.forEach(label => {
|
||||
label.style.width = '';
|
||||
label.textContent += extraText;
|
||||
});
|
||||
|
||||
mutationCallbacks.forEach(callback => callback());
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(tabHeaderElement.classList).toContain(enabledClass);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -359,7 +395,7 @@ interface Tab {
|
||||
<mat-tab-header [selectedIndex]="selectedIndex" [disableRipple]="disableRipple"
|
||||
(indexFocused)="focusedIndex = $event"
|
||||
(selectFocusedIndex)="selectedIndex = $event">
|
||||
<div matTabLabelWrapper style="min-width: 30px; width: 30px"
|
||||
<div matTabLabelWrapper class="label-content" style="min-width: 30px; width: 30px"
|
||||
*ngFor="let tab of tabs; let i = index"
|
||||
[disabled]="!!tab.disabled"
|
||||
(click)="selectedIndex = i">
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
Input,
|
||||
NgZone,
|
||||
OnDestroy,
|
||||
Optional,
|
||||
Output,
|
||||
@@ -137,7 +138,9 @@ export class MatTabHeader extends _MatTabHeaderMixinBase
|
||||
constructor(private _elementRef: ElementRef,
|
||||
private _changeDetectorRef: ChangeDetectorRef,
|
||||
private _viewportRuler: ViewportRuler,
|
||||
@Optional() private _dir: Directionality) {
|
||||
@Optional() private _dir: Directionality,
|
||||
// @breaking-change 8.0.0 `_ngZone` parameter to be made required.
|
||||
private _ngZone?: NgZone) {
|
||||
super();
|
||||
}
|
||||
|
||||
@@ -234,9 +237,16 @@ export class MatTabHeader extends _MatTabHeaderMixinBase
|
||||
* Callback for when the MutationObserver detects that the content has changed.
|
||||
*/
|
||||
_onContentChanges() {
|
||||
this._updatePagination();
|
||||
this._alignInkBarToSelectedTab();
|
||||
this._changeDetectorRef.markForCheck();
|
||||
const zoneCallback = () => {
|
||||
this._updatePagination();
|
||||
this._alignInkBarToSelectedTab();
|
||||
this._changeDetectorRef.markForCheck();
|
||||
};
|
||||
|
||||
// The content observer runs outside the `NgZone` by default, which
|
||||
// means that we need to bring the callback back in ourselves.
|
||||
// @breaking-change 8.0.0 Remove null check for `_ngZone` once it's a required parameter.
|
||||
this._ngZone ? this._ngZone.run(zoneCallback) : zoneCallback();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user