mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
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.
This commit is contained in:
committed by
Jeremy Elbourn
parent
efb39da377
commit
21f88999bb
@@ -29,7 +29,7 @@ describe('MdTextareaAutosize', () => {
|
||||
});
|
||||
|
||||
it('should resize the textarea based on its content', () => {
|
||||
let previousHeight = textarea.offsetHeight;
|
||||
let previousHeight = textarea.clientHeight;
|
||||
|
||||
fixture.componentInstance.content = `
|
||||
Once upon a midnight dreary, while I pondered, weak and weary,
|
||||
@@ -43,12 +43,12 @@ describe('MdTextareaAutosize', () => {
|
||||
fixture.detectChanges();
|
||||
autosize.resizeToFitContent();
|
||||
|
||||
expect(textarea.offsetHeight)
|
||||
expect(textarea.clientHeight)
|
||||
.toBeGreaterThan(previousHeight, 'Expected textarea to have grown with added content.');
|
||||
expect(textarea.offsetHeight)
|
||||
expect(textarea.clientHeight)
|
||||
.toBe(textarea.scrollHeight, 'Expected textarea height to match its scrollHeight');
|
||||
|
||||
previousHeight = textarea.offsetHeight;
|
||||
previousHeight = textarea.clientHeight;
|
||||
fixture.componentInstance.content += `
|
||||
Ah, distinctly I remember it was in the bleak December;
|
||||
And each separate dying ember wrought its ghost upon the floor.
|
||||
@@ -60,9 +60,9 @@ describe('MdTextareaAutosize', () => {
|
||||
fixture.detectChanges();
|
||||
autosize.resizeToFitContent();
|
||||
|
||||
expect(textarea.offsetHeight)
|
||||
expect(textarea.clientHeight)
|
||||
.toBeGreaterThan(previousHeight, 'Expected textarea to have grown with added content.');
|
||||
expect(textarea.offsetHeight)
|
||||
expect(textarea.clientHeight)
|
||||
.toBe(textarea.scrollHeight, 'Expected textarea height to match its scrollHeight');
|
||||
});
|
||||
|
||||
@@ -103,6 +103,27 @@ describe('MdTextareaAutosize', () => {
|
||||
expect(fixture.componentInstance.autosize.resizeToFitContent).toBeTruthy();
|
||||
});
|
||||
|
||||
|
||||
it('should properly resize to content on init', () => {
|
||||
// Manually create the test component in this test, because in this test the first change
|
||||
// detection should be triggered after a multiline content is set.
|
||||
fixture = TestBed.createComponent(AutosizeTextAreaWithContent);
|
||||
textarea = fixture.nativeElement.querySelector('textarea');
|
||||
autosize = fixture.debugElement.query(By.css('textarea')).injector.get(MdTextareaAutosize);
|
||||
|
||||
fixture.componentInstance.content = `
|
||||
Line
|
||||
Line
|
||||
Line
|
||||
Line
|
||||
Line`;
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(textarea.clientHeight)
|
||||
.toBe(textarea.scrollHeight, 'Expected textarea height to match its scrollHeight');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Directive, ElementRef, Input, OnInit} from '@angular/core';
|
||||
import {Directive, ElementRef, Input, AfterViewInit} from '@angular/core';
|
||||
|
||||
|
||||
/**
|
||||
@@ -14,7 +14,7 @@ import {Directive, ElementRef, Input, OnInit} from '@angular/core';
|
||||
'[style.max-height]': '_maxHeight',
|
||||
},
|
||||
})
|
||||
export class MdTextareaAutosize implements OnInit {
|
||||
export class MdTextareaAutosize implements AfterViewInit {
|
||||
/** @deprecated Use mdAutosizeMinRows */
|
||||
@Input() minRows: number;
|
||||
|
||||
@@ -46,7 +46,7 @@ export class MdTextareaAutosize implements OnInit {
|
||||
return this.maxRows ? `${this.maxRows * this._cachedLineHeight}px` : null;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
ngAfterViewInit() {
|
||||
this._cacheTextareaLineHeight();
|
||||
this.resizeToFitContent();
|
||||
}
|
||||
@@ -71,13 +71,13 @@ export class MdTextareaAutosize implements OnInit {
|
||||
textareaClone.style.position = 'absolute';
|
||||
textareaClone.style.visibility = 'hidden';
|
||||
textareaClone.style.border = 'none';
|
||||
textareaClone.style.padding = '';
|
||||
textareaClone.style.padding = '0';
|
||||
textareaClone.style.height = '';
|
||||
textareaClone.style.minHeight = '';
|
||||
textareaClone.style.maxHeight = '';
|
||||
|
||||
textarea.parentNode.appendChild(textareaClone);
|
||||
this._cachedLineHeight = textareaClone.offsetHeight;
|
||||
this._cachedLineHeight = textareaClone.clientHeight;
|
||||
textarea.parentNode.removeChild(textareaClone);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user