From 89fea5053cbcd521f4d4934c103c1f993961b536 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 1 Sep 2017 16:59:47 +0200 Subject: [PATCH] fix(autosize): not resizing on programmatic changes (#6654) 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. --- src/lib/input/autosize.spec.ts | 19 ++++++++++++++++++- src/lib/input/autosize.ts | 26 +++++++++++--------------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/lib/input/autosize.spec.ts b/src/lib/input/autosize.spec.ts index e868c7cb63b1..f8fd600f97ae 100644 --- a/src/lib/input/autosize.spec.ts +++ b/src/lib/input/autosize.spec.ts @@ -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 @@ -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.'); + })); }); diff --git a/src/lib/input/autosize.ts b/src/lib/input/autosize.ts index 3a4e489a3a4d..ecb135b8ce7b 100644 --- a/src/lib/input/autosize.ts +++ b/src/lib/input/autosize.ts @@ -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'; @@ -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; @@ -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 { @@ -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; } @@ -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; } }