Skip to content

fix(autosize): incorrect height with long placeholders #8024

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 45 additions & 2 deletions src/lib/input/autosize.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ describe('MatTextareaAutosize', () => {
AutosizeTextareaInATab,
AutosizeTextAreaWithContent,
AutosizeTextAreaWithValue,
AutosizeTextareaWithNgModel
AutosizeTextareaWithNgModel,
AutosizeTextareaWithLongPlaceholder
],
});

Expand Down Expand Up @@ -176,6 +177,27 @@ describe('MatTextareaAutosize', () => {
.toBe(textarea.scrollHeight, 'Expected textarea height to match its scrollHeight');
});

it('should not calculate wrong content height due to long placeholders', () => {
const fixtureWithPlaceholder = TestBed.createComponent(AutosizeTextareaWithLongPlaceholder);
fixtureWithPlaceholder.detectChanges();

textarea = fixtureWithPlaceholder.nativeElement.querySelector('textarea');
autosize = fixtureWithPlaceholder.debugElement.query(
By.directive(MatTextareaAutosize)).injector.get<MatTextareaAutosize>(MatTextareaAutosize);

triggerTextareaResize();

const heightWithLongPlaceholder = textarea.clientHeight;

fixtureWithPlaceholder.componentInstance.placeholder = 'Short';
fixtureWithPlaceholder.detectChanges();

triggerTextareaResize();

expect(textarea.clientHeight).toBe(heightWithLongPlaceholder,
'Expected the textarea height to be the same with a long placeholder.');
});

it('should resize when an associated form control value changes', fakeAsync(() => {
const fixtureWithForms = TestBed.createComponent(AutosizeTextareaWithNgModel);
textarea = fixtureWithForms.nativeElement.querySelector('textarea');
Expand Down Expand Up @@ -227,8 +249,18 @@ describe('MatTextareaAutosize', () => {
textarea = fixtureWithForms.nativeElement.querySelector('textarea');
expect(textarea.getBoundingClientRect().height).toBeGreaterThan(1);
});
});

/** Triggers a textarea resize to fit the content. */
function triggerTextareaResize() {
// To be able to trigger a new calculation of the height with a short placeholder, the
// textarea value needs to be changed.
textarea.value = '1';
autosize.resizeToFitContent();

textarea.value = '';
autosize.resizeToFitContent();
}
});

// Styles to reset padding and border to make measurement comparisons easier.
const textareaStyleReset = `
Expand Down Expand Up @@ -269,6 +301,17 @@ class AutosizeTextareaWithNgModel {
model = '';
}

@Component({
template: `
<mat-form-field style="width: 100px">
<textarea matInput matTextareaAutosize [placeholder]="placeholder"></textarea>
</mat-form-field>`,
styles: [textareaStyleReset],
})
class AutosizeTextareaWithLongPlaceholder {
placeholder = 'Long Long Long Long Long Long Long Long Placeholder';
}

@Component({
template: `
<mat-tab-group>
Expand Down
7 changes: 7 additions & 0 deletions src/lib/input/autosize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,21 @@ export class MatTextareaAutosize implements AfterViewInit, DoCheck {
return;
}

const placeholderText = textarea.placeholder;

// Reset the textarea height to auto in order to shrink back to its default size.
// Also temporarily force overflow:hidden, so scroll bars do not interfere with calculations.
// Long placeholders that are wider than the textarea width may lead to a bigger scrollHeight
// value. To ensure that the scrollHeight is not bigger than the content, the placeholders
// need to be removed temporarily.
textarea.style.height = 'auto';
textarea.style.overflow = 'hidden';
textarea.placeholder = '';

// Use the scrollHeight to know how large the textarea *would* be if fit its entire value.
textarea.style.height = `${textarea.scrollHeight}px`;
textarea.style.overflow = '';
textarea.placeholder = placeholderText;

this._previousValue = value;
}
Expand Down