Skip to content

Commit ad7cb4a

Browse files
devversionjelbourn
authored andcommitted
fix(autosize): incorrect height with long placeholders (#8024)
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 3037a90 commit ad7cb4a

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

src/lib/input/autosize.spec.ts

Lines changed: 45 additions & 2 deletions
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,27 @@ 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+
triggerTextareaResize();
189+
190+
const heightWithLongPlaceholder = textarea.clientHeight;
191+
192+
fixtureWithPlaceholder.componentInstance.placeholder = 'Short';
193+
fixtureWithPlaceholder.detectChanges();
194+
195+
triggerTextareaResize();
196+
197+
expect(textarea.clientHeight).toBe(heightWithLongPlaceholder,
198+
'Expected the textarea height to be the same with a long placeholder.');
199+
});
200+
179201
it('should resize when an associated form control value changes', fakeAsync(() => {
180202
const fixtureWithForms = TestBed.createComponent(AutosizeTextareaWithNgModel);
181203
textarea = fixtureWithForms.nativeElement.querySelector('textarea');
@@ -227,8 +249,18 @@ describe('MatTextareaAutosize', () => {
227249
textarea = fixtureWithForms.nativeElement.querySelector('textarea');
228250
expect(textarea.getBoundingClientRect().height).toBeGreaterThan(1);
229251
});
230-
});
231252

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();
259+
260+
textarea.value = '';
261+
autosize.resizeToFitContent();
262+
}
263+
});
232264

233265
// Styles to reset padding and border to make measurement comparisons easier.
234266
const textareaStyleReset = `
@@ -269,6 +301,17 @@ class AutosizeTextareaWithNgModel {
269301
model = '';
270302
}
271303

304+
@Component({
305+
template: `
306+
<mat-form-field style="width: 100px">
307+
<textarea matInput matTextareaAutosize [placeholder]="placeholder"></textarea>
308+
</mat-form-field>`,
309+
styles: [textareaStyleReset],
310+
})
311+
class AutosizeTextareaWithLongPlaceholder {
312+
placeholder = 'Long Long Long Long Long Long Long Long Placeholder';
313+
}
314+
272315
@Component({
273316
template: `
274317
<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 placeholderText = 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 = placeholderText;
161168

162169
this._previousValue = value;
163170
}

0 commit comments

Comments
 (0)