Skip to content

Commit 7615b21

Browse files
committed
fix(autosize): incorrect height with long placeholders
Long placeholders can cause the `scrollHeight` to be bigger than the actual content is. To ensure the `scrollHeight` is correct, the placeholders need to be removed temporarily. Fixes #8013
1 parent 0f954a0 commit 7615b21

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

src/lib/input/autosize.spec.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ describe('MatTextareaAutosize', () => {
2828
AutosizeTextareaInATab,
2929
AutosizeTextAreaWithContent,
3030
AutosizeTextAreaWithValue,
31-
AutosizeTextareaWithNgModel
31+
AutosizeTextareaWithNgModel,
32+
AutosizeTextareaWithLongPlaceholder
3233
],
3334
});
3435

@@ -176,6 +177,39 @@ describe('MatTextareaAutosize', () => {
176177
.toBe(textarea.scrollHeight, 'Expected textarea height to match its scrollHeight');
177178
});
178179

180+
it('should not calculate wrong content height due to long placeholders', () => {
181+
const fixtureWithPlaceholder = TestBed.createComponent(AutosizeTextareaWithLongPlaceholder);
182+
fixtureWithPlaceholder.detectChanges();
183+
184+
textarea = fixtureWithPlaceholder.nativeElement.querySelector('textarea');
185+
autosize = fixtureWithPlaceholder.debugElement.query(
186+
By.directive(MatTextareaAutosize)).injector.get<MatTextareaAutosize>(MatTextareaAutosize);
187+
188+
// To be able to trigger a new calculation of the height with a long placeholder, the textarea
189+
// value needs to be changed.
190+
textarea.value = '1';
191+
autosize.resizeToFitContent();
192+
193+
textarea.value = '';
194+
autosize.resizeToFitContent();
195+
196+
const heightWithLongPlaceholder = textarea.clientHeight;
197+
198+
fixtureWithPlaceholder.componentInstance.placeholder = 'Short';
199+
fixtureWithPlaceholder.detectChanges();
200+
201+
// To be able to trigger a new calculation of the height with a short placeholder, the
202+
// textarea value needs to be changed.
203+
textarea.value = '1';
204+
autosize.resizeToFitContent();
205+
206+
textarea.value = '';
207+
autosize.resizeToFitContent();
208+
209+
expect(textarea.clientHeight).toBe(heightWithLongPlaceholder,
210+
'Expected the textarea height to be the same with a long placeholder.');
211+
});
212+
179213
it('should resize when an associated form control value changes', fakeAsync(() => {
180214
const fixtureWithForms = TestBed.createComponent(AutosizeTextareaWithNgModel);
181215
textarea = fixtureWithForms.nativeElement.querySelector('textarea');
@@ -269,6 +303,17 @@ class AutosizeTextareaWithNgModel {
269303
model = '';
270304
}
271305

306+
@Component({
307+
template: `
308+
<mat-form-field style="width: 100px">
309+
<textarea matInput matTextareaAutosize [placeholder]="placeholder"></textarea>
310+
</mat-form-field>`,
311+
styles: [textareaStyleReset],
312+
})
313+
class AutosizeTextareaWithLongPlaceholder {
314+
placeholder = 'Long Long Long Long Long Long Long Long Placeholder';
315+
}
316+
272317
@Component({
273318
template: `
274319
<mat-tab-group>

src/lib/input/autosize.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,21 @@ export class MatTextareaAutosize implements AfterViewInit, DoCheck {
150150
return;
151151
}
152152

153+
const previousPlaceholder = textarea.placeholder;
154+
153155
// Reset the textarea height to auto in order to shrink back to its default size.
154156
// Also temporarily force overflow:hidden, so scroll bars do not interfere with calculations.
157+
// Long placeholders that are wider than the textarea width may lead to a bigger scrollHeight
158+
// value. To ensure that the scrollHeight is not bigger than the content, the placeholders
159+
// need to be removed temporarily.
155160
textarea.style.height = 'auto';
156161
textarea.style.overflow = 'hidden';
162+
textarea.placeholder = '';
157163

158164
// Use the scrollHeight to know how large the textarea *would* be if fit its entire value.
159165
textarea.style.height = `${textarea.scrollHeight}px`;
160166
textarea.style.overflow = '';
167+
textarea.placeholder = previousPlaceholder;
161168

162169
this._previousValue = value;
163170
}

0 commit comments

Comments
 (0)