Skip to content

Commit 23d4f08

Browse files
committed
fix(autosize): not updating when window is resized
Fixes the autosize textarea not recalculating its height when the viewport size has changed. Fixes #8610.
1 parent 6e865b7 commit 23d4f08

File tree

2 files changed

+48
-20
lines changed

2 files changed

+48
-20
lines changed

src/lib/input/autosize.spec.ts

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import {Component, ViewChild} from '@angular/core';
22
import {FormsModule} from '@angular/forms';
3-
import {ComponentFixture, TestBed, async, fakeAsync, flushMicrotasks} from '@angular/core/testing';
3+
import {ComponentFixture, TestBed, async, fakeAsync, flush, tick} from '@angular/core/testing';
44
import {By} from '@angular/platform-browser';
55
import {MatInputModule} from './index';
66
import {MatTextareaAutosize} from './autosize';
77
import {MatStepperModule} from '@angular/material/stepper';
88
import {MatTabsModule} from '@angular/material/tabs';
99
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
10+
import {dispatchFakeEvent} from '@angular/cdk/testing';
1011

1112

1213
describe('MatTextareaAutosize', () => {
@@ -185,14 +186,14 @@ describe('MatTextareaAutosize', () => {
185186
autosize = fixtureWithPlaceholder.debugElement.query(
186187
By.directive(MatTextareaAutosize)).injector.get<MatTextareaAutosize>(MatTextareaAutosize);
187188

188-
triggerTextareaResize();
189+
autosize.resizeToFitContent(true);
189190

190191
const heightWithLongPlaceholder = textarea.clientHeight;
191192

192193
fixtureWithPlaceholder.componentInstance.placeholder = 'Short';
193194
fixtureWithPlaceholder.detectChanges();
194195

195-
triggerTextareaResize();
196+
autosize.resizeToFitContent(true);
196197

197198
expect(textarea.clientHeight).toBe(heightWithLongPlaceholder,
198199
'Expected the textarea height to be the same with a long placeholder.');
@@ -213,7 +214,7 @@ describe('MatTextareaAutosize', () => {
213214
Some late visitor entreating entrance at my chamber door;—
214215
This it is and nothing more.” `;
215216
fixtureWithForms.detectChanges();
216-
flushMicrotasks();
217+
flush();
217218
fixtureWithForms.detectChanges();
218219

219220
expect(textarea.clientHeight)
@@ -229,7 +230,7 @@ describe('MatTextareaAutosize', () => {
229230
`;
230231

231232
fixture.detectChanges();
232-
flushMicrotasks();
233+
flush();
233234
fixture.detectChanges();
234235

235236
expect(textarea.clientHeight)
@@ -250,16 +251,14 @@ describe('MatTextareaAutosize', () => {
250251
expect(textarea.getBoundingClientRect().height).toBeGreaterThan(1);
251252
});
252253

253-
/** Triggers a textarea resize to fit the content. */
254-
function triggerTextareaResize() {
255-
// To be able to trigger a new calculation of the height with a short placeholder, the
256-
// textarea value needs to be changed.
257-
textarea.value = '1';
258-
autosize.resizeToFitContent();
254+
it('should trigger a resize when the window is resized', fakeAsync(() => {
255+
spyOn(autosize, 'resizeToFitContent');
259256

260-
textarea.value = '';
261-
autosize.resizeToFitContent();
262-
}
257+
dispatchFakeEvent(window, 'resize');
258+
tick(10);
259+
260+
expect(autosize.resizeToFitContent).toHaveBeenCalled();
261+
}));
263262
});
264263

265264
// Styles to reset padding and border to make measurement comparisons easier.

src/lib/input/autosize.ts

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,19 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Directive, ElementRef, Input, AfterViewInit, DoCheck} from '@angular/core';
9+
import {
10+
Directive,
11+
ElementRef,
12+
Input,
13+
AfterViewInit,
14+
DoCheck,
15+
OnDestroy,
16+
NgZone,
17+
} from '@angular/core';
1018
import {Platform} from '@angular/cdk/platform';
19+
import {fromEvent} from 'rxjs/observable/fromEvent';
20+
import {debounceTime} from 'rxjs/operators/debounceTime';
21+
import {Subscription} from 'rxjs/Subscription';
1122

1223

1324
/**
@@ -22,9 +33,10 @@ import {Platform} from '@angular/cdk/platform';
2233
'rows': '1',
2334
},
2435
})
25-
export class MatTextareaAutosize implements AfterViewInit, DoCheck {
36+
export class MatTextareaAutosize implements AfterViewInit, DoCheck, OnDestroy {
2637
/** Keep track of the previous textarea value to avoid resizing when the value hasn't changed. */
2738
private _previousValue: string;
39+
private _resize = Subscription.EMPTY;
2840

2941
private _minRows: number;
3042
private _maxRows: number;
@@ -47,7 +59,10 @@ export class MatTextareaAutosize implements AfterViewInit, DoCheck {
4759
/** Cached height of a textarea with a single row. */
4860
private _cachedLineHeight: number;
4961

50-
constructor(private _elementRef: ElementRef, private _platform: Platform) {}
62+
constructor(
63+
private _elementRef: ElementRef,
64+
private _platform: Platform,
65+
private _ngZone: NgZone) {}
5166

5267
/** Sets the minimum height of the textarea as determined by minRows. */
5368
_setMinHeight(): void {
@@ -72,9 +87,19 @@ export class MatTextareaAutosize implements AfterViewInit, DoCheck {
7287
ngAfterViewInit() {
7388
if (this._platform.isBrowser) {
7489
this.resizeToFitContent();
90+
91+
this._resize = this._ngZone.runOutsideAngular(() => {
92+
return fromEvent(window, 'resize')
93+
.pipe(debounceTime(10))
94+
.subscribe(() => this.resizeToFitContent(true));
95+
});
7596
}
7697
}
7798

99+
ngOnDestroy() {
100+
this._resize.unsubscribe();
101+
}
102+
78103
/** Sets a style property on the textarea element. */
79104
private _setTextareaStyle(property: string, value: string): void {
80105
const textarea = this._elementRef.nativeElement as HTMLTextAreaElement;
@@ -132,8 +157,12 @@ export class MatTextareaAutosize implements AfterViewInit, DoCheck {
132157
}
133158
}
134159

135-
/** Resize the textarea to fit its content. */
136-
resizeToFitContent() {
160+
/**
161+
* Resize the textarea to fit its content.
162+
* @param force Whether to force a height recalculation. By default the height will be
163+
* recalculated only if the value changed since the last call.
164+
*/
165+
resizeToFitContent(force = false) {
137166
this._cacheTextareaLineHeight();
138167

139168
// If we haven't determined the line-height yet, we know we're still hidden and there's no point
@@ -146,7 +175,7 @@ export class MatTextareaAutosize implements AfterViewInit, DoCheck {
146175
const value = textarea.value;
147176

148177
// Only resize of the value changed since these calculations can be expensive.
149-
if (value === this._previousValue) {
178+
if (value === this._previousValue && !force) {
150179
return;
151180
}
152181

0 commit comments

Comments
 (0)