Skip to content

Commit

Permalink
fix(autosize): not resizing on programmatic changes (#6654)
Browse files Browse the repository at this point in the history
Fixes the textarea autosize directive not resizing when the value is changed programmatically outside Angular (e.g. `element.value`) or when the form control is swapped out.

Fixes #5247.
  • Loading branch information
crisbeto authored and jelbourn committed Sep 1, 2017
1 parent 67e02b0 commit 89fea50
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 16 deletions.
19 changes: 18 additions & 1 deletion src/lib/input/autosize.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ describe('MdTextareaAutosize', () => {
textarea = fixtureWithForms.nativeElement.querySelector('textarea');
fixtureWithForms.detectChanges();

const previousHeight = textarea.clientHeight;
const previousHeight = textarea.clientHeight;

fixtureWithForms.componentInstance.model = `
And the silken, sad, uncertain rustling of each purple curtain
Expand All @@ -181,10 +181,27 @@ describe('MdTextareaAutosize', () => {
This it is and nothing more.” `;
fixtureWithForms.detectChanges();
flushMicrotasks();
fixtureWithForms.detectChanges();

expect(textarea.clientHeight)
.toBeGreaterThan(previousHeight, 'Expected increased height when ngModel is updated.');
}));

it('should resize when the textarea value is changed programmatically', fakeAsync(() => {
const previousHeight = textarea.clientHeight;

textarea.value = `
How much wood would a woodchuck chuck
if a woodchuck could chuck wood?
`;

fixture.detectChanges();
flushMicrotasks();
fixture.detectChanges();

expect(textarea.clientHeight)
.toBeGreaterThan(previousHeight, 'Expected the textarea height to have increased.');
}));
});


Expand Down
26 changes: 11 additions & 15 deletions src/lib/input/autosize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Directive, ElementRef, Input, AfterViewInit, Optional, Self} from '@angular/core';
import {NgControl} from '@angular/forms';
import {Directive, ElementRef, Input, AfterViewInit, DoCheck} from '@angular/core';
import {Platform} from '@angular/cdk/platform';


Expand All @@ -19,13 +18,12 @@ import {Platform} from '@angular/cdk/platform';
textarea[mat-autosize], textarea[matTextareaAutosize]`,
exportAs: 'mdTextareaAutosize',
host: {
'(input)': 'resizeToFitContent()',
// Textarea elements that have the directive applied should have a single row by default.
// Browsers normally show two rows by default and therefore this limits the minRows binding.
'rows': '1',
},
})
export class MdTextareaAutosize implements AfterViewInit {
export class MdTextareaAutosize implements AfterViewInit, DoCheck {
/** Keep track of the previous textarea value to avoid resizing when the value hasn't changed. */
private _previousValue: string;

Expand Down Expand Up @@ -58,15 +56,7 @@ export class MdTextareaAutosize implements AfterViewInit {
/** Cached height of a textarea with a single row. */
private _cachedLineHeight: number;

constructor(
private _elementRef: ElementRef,
private _platform: Platform,
@Optional() @Self() formControl: NgControl) {

if (formControl && formControl.valueChanges) {
formControl.valueChanges.subscribe(() => this.resizeToFitContent());
}
}
constructor(private _elementRef: ElementRef, private _platform: Platform) {}

/** Sets the minimum height of the textarea as determined by minRows. */
_setMinHeight(): void {
Expand Down Expand Up @@ -142,11 +132,17 @@ export class MdTextareaAutosize implements AfterViewInit {
this._setMaxHeight();
}

ngDoCheck() {
this.resizeToFitContent();
}

/** Resize the textarea to fit its content. */
resizeToFitContent() {
const textarea = this._elementRef.nativeElement as HTMLTextAreaElement;
const value = textarea.value;

if (textarea.value === this._previousValue) {
// Only resize of the value changed since these calculations can be expensive.
if (value === this._previousValue) {
return;
}

Expand All @@ -159,6 +155,6 @@ export class MdTextareaAutosize implements AfterViewInit {
textarea.style.height = `${textarea.scrollHeight}px`;
textarea.style.overflow = '';

this._previousValue = textarea.value;
this._previousValue = value;
}
}

0 comments on commit 89fea50

Please sign in to comment.