Skip to content

Commit 21f8899

Browse files
devversionjelbourn
authored andcommitted
fix(input): incorrect height with autosize (#4084)
Currently when using the `mdTextareaAutosize` directive the textarea height might be incorrect on component initialization. This happens because the textarea `scrollHeight` property is not ready in the `ngOnInit` lifecycle hook yet. Other libraries like `angular-elastic` have timeouts for that. But using the `ngAfterViewInit` lifecycle hook is more elegant and also ensures that the `scrollHeight` property is ready. Also switches `offsetHeight` to `clientHeight` since we don't want to include the border in our line-height calculations. Also by default `textarea` elements have a padding of `2px` and the `padding` needs to be explicitly set to `0px` when resolving the line-height. Fixes #4070.
1 parent efb39da commit 21f8899

File tree

2 files changed

+32
-11
lines changed

2 files changed

+32
-11
lines changed

src/lib/input/autosize.spec.ts

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ describe('MdTextareaAutosize', () => {
2929
});
3030

3131
it('should resize the textarea based on its content', () => {
32-
let previousHeight = textarea.offsetHeight;
32+
let previousHeight = textarea.clientHeight;
3333

3434
fixture.componentInstance.content = `
3535
Once upon a midnight dreary, while I pondered, weak and weary,
@@ -43,12 +43,12 @@ describe('MdTextareaAutosize', () => {
4343
fixture.detectChanges();
4444
autosize.resizeToFitContent();
4545

46-
expect(textarea.offsetHeight)
46+
expect(textarea.clientHeight)
4747
.toBeGreaterThan(previousHeight, 'Expected textarea to have grown with added content.');
48-
expect(textarea.offsetHeight)
48+
expect(textarea.clientHeight)
4949
.toBe(textarea.scrollHeight, 'Expected textarea height to match its scrollHeight');
5050

51-
previousHeight = textarea.offsetHeight;
51+
previousHeight = textarea.clientHeight;
5252
fixture.componentInstance.content += `
5353
Ah, distinctly I remember it was in the bleak December;
5454
And each separate dying ember wrought its ghost upon the floor.
@@ -60,9 +60,9 @@ describe('MdTextareaAutosize', () => {
6060
fixture.detectChanges();
6161
autosize.resizeToFitContent();
6262

63-
expect(textarea.offsetHeight)
63+
expect(textarea.clientHeight)
6464
.toBeGreaterThan(previousHeight, 'Expected textarea to have grown with added content.');
65-
expect(textarea.offsetHeight)
65+
expect(textarea.clientHeight)
6666
.toBe(textarea.scrollHeight, 'Expected textarea height to match its scrollHeight');
6767
});
6868

@@ -103,6 +103,27 @@ describe('MdTextareaAutosize', () => {
103103
expect(fixture.componentInstance.autosize.resizeToFitContent).toBeTruthy();
104104
});
105105

106+
107+
it('should properly resize to content on init', () => {
108+
// Manually create the test component in this test, because in this test the first change
109+
// detection should be triggered after a multiline content is set.
110+
fixture = TestBed.createComponent(AutosizeTextAreaWithContent);
111+
textarea = fixture.nativeElement.querySelector('textarea');
112+
autosize = fixture.debugElement.query(By.css('textarea')).injector.get(MdTextareaAutosize);
113+
114+
fixture.componentInstance.content = `
115+
Line
116+
Line
117+
Line
118+
Line
119+
Line`;
120+
121+
fixture.detectChanges();
122+
123+
expect(textarea.clientHeight)
124+
.toBe(textarea.scrollHeight, 'Expected textarea height to match its scrollHeight');
125+
});
126+
106127
});
107128

108129

src/lib/input/autosize.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Directive, ElementRef, Input, OnInit} from '@angular/core';
1+
import {Directive, ElementRef, Input, AfterViewInit} from '@angular/core';
22

33

44
/**
@@ -14,7 +14,7 @@ import {Directive, ElementRef, Input, OnInit} from '@angular/core';
1414
'[style.max-height]': '_maxHeight',
1515
},
1616
})
17-
export class MdTextareaAutosize implements OnInit {
17+
export class MdTextareaAutosize implements AfterViewInit {
1818
/** @deprecated Use mdAutosizeMinRows */
1919
@Input() minRows: number;
2020

@@ -46,7 +46,7 @@ export class MdTextareaAutosize implements OnInit {
4646
return this.maxRows ? `${this.maxRows * this._cachedLineHeight}px` : null;
4747
}
4848

49-
ngOnInit() {
49+
ngAfterViewInit() {
5050
this._cacheTextareaLineHeight();
5151
this.resizeToFitContent();
5252
}
@@ -71,13 +71,13 @@ export class MdTextareaAutosize implements OnInit {
7171
textareaClone.style.position = 'absolute';
7272
textareaClone.style.visibility = 'hidden';
7373
textareaClone.style.border = 'none';
74-
textareaClone.style.padding = '';
74+
textareaClone.style.padding = '0';
7575
textareaClone.style.height = '';
7676
textareaClone.style.minHeight = '';
7777
textareaClone.style.maxHeight = '';
7878

7979
textarea.parentNode.appendChild(textareaClone);
80-
this._cachedLineHeight = textareaClone.offsetHeight;
80+
this._cachedLineHeight = textareaClone.clientHeight;
8181
textarea.parentNode.removeChild(textareaClone);
8282
}
8383

0 commit comments

Comments
 (0)