Skip to content

Commit

Permalink
WIP: feat(cdk-input): change autosize to be bindable (angular#9884)
Browse files Browse the repository at this point in the history
This allows cdkTextareaAutosize selector to be bindable and toggle the internal
enabled / disabled state.

Upon disabling the initial height is restored (textarea.style.height before any changes
were applied).

Also added wrapper into (to be discontinued) matTextareaAutosize.

Fixes angular#9884

Currently missing unit tests, thus still WIP. Manual tests in demo-app seem to work as expected
  • Loading branch information
pfeigl committed May 4, 2018
1 parent ab1204d commit 3915e08
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 7 deletions.
49 changes: 42 additions & 7 deletions src/cdk/text-field/autosize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {
Directive,
ElementRef,
Expand Down Expand Up @@ -35,10 +36,16 @@ import {fromEvent, Subject} from 'rxjs';
export class CdkTextareaAutosize implements AfterViewInit, DoCheck, OnDestroy {
/** Keep track of the previous textarea value to avoid resizing when the value hasn't changed. */
private _previousValue: string;
private _initialHeight: string | null;
private readonly _destroyed = new Subject<void>();

private _minRows: number;
private _maxRows: number;
private _enabled: boolean = true;

private get textarea(): HTMLTextAreaElement {
return this._elementRef.nativeElement as HTMLTextAreaElement;
}

/** Minimum amount of rows in the textarea. */
@Input('cdkAutosizeMinRows')
Expand All @@ -56,6 +63,19 @@ export class CdkTextareaAutosize implements AfterViewInit, DoCheck, OnDestroy {
this._setMaxHeight();
}

/** Whether autosizing is enabled or not */
@Input('cdkTextareaAutosize')
get enabled(): boolean { return this._enabled; }
set enabled(value: boolean) {
value = coerceBooleanProperty(value);

// Only act if the actual value changed. This specifically helps to not run
// resizeToFitContent too early (i.e. before ngAfterViewInit)
if (this._enabled !== value) {
(this._enabled = value) ? this.resizeToFitContent(true) : this.reset();
}
}

/** Cached height of a textarea with a single row. */
private _cachedLineHeight: number;

Expand Down Expand Up @@ -86,6 +106,9 @@ export class CdkTextareaAutosize implements AfterViewInit, DoCheck, OnDestroy {

ngAfterViewInit() {
if (this._platform.isBrowser) {
// Remember the height which we started with in case autosizing is disabled
this._initialHeight = this.textarea.style.height;

this.resizeToFitContent();

this._ngZone.runOutsideAngular(() => {
Expand All @@ -103,8 +126,7 @@ export class CdkTextareaAutosize implements AfterViewInit, DoCheck, OnDestroy {

/** Sets a style property on the textarea element. */
private _setTextareaStyle(property: string, value: string): void {
const textarea = this._elementRef.nativeElement as HTMLTextAreaElement;
textarea.style[property] = value;
this.textarea.style[property] = value;
}

/**
Expand All @@ -119,10 +141,8 @@ export class CdkTextareaAutosize implements AfterViewInit, DoCheck, OnDestroy {
return;
}

let textarea = this._elementRef.nativeElement as HTMLTextAreaElement;

// Use a clone element because we have to override some styles.
let textareaClone = textarea.cloneNode(false) as HTMLTextAreaElement;
let textareaClone = this.textarea.cloneNode(false) as HTMLTextAreaElement;
textareaClone.rows = 1;

// Use `position: absolute` so that this doesn't cause a browser layout and use
Expand All @@ -143,9 +163,9 @@ export class CdkTextareaAutosize implements AfterViewInit, DoCheck, OnDestroy {
// See Firefox bug report: https://bugzilla.mozilla.org/show_bug.cgi?id=33654
textareaClone.style.overflow = 'hidden';

textarea.parentNode!.appendChild(textareaClone);
this.textarea.parentNode!.appendChild(textareaClone);
this._cachedLineHeight = textareaClone.clientHeight;
textarea.parentNode!.removeChild(textareaClone);
this.textarea.parentNode!.removeChild(textareaClone);

// Min and max heights have to be re-calculated if the cached line height changes
this._setMinHeight();
Expand All @@ -164,6 +184,11 @@ export class CdkTextareaAutosize implements AfterViewInit, DoCheck, OnDestroy {
* recalculated only if the value changed since the last call.
*/
resizeToFitContent(force: boolean = false) {
// If autosizing is disabled, just skip everything else
if (!this._enabled) {
return;
}

this._cacheTextareaLineHeight();

// If we haven't determined the line-height yet, we know we're still hidden and there's no point
Expand Down Expand Up @@ -211,6 +236,16 @@ export class CdkTextareaAutosize implements AfterViewInit, DoCheck, OnDestroy {
this._previousValue = value;
}

/**
* Resets the textarea to it's original size
*/
reset() {
if (this._initialHeight === undefined) {
return;
}
this.textarea.style.height = this._initialHeight;
}

_noopInputHandler() {
// no-op handler that ensures we're running change detection on input events.
}
Expand Down
6 changes: 6 additions & 0 deletions src/demo-app/input/input-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,12 @@ <h3>&lt;textarea&gt; with ngModel</h3>
Plain textarea with auto size
<textarea cdkTextareaAutosize [(ngModel)]="textareaNgModelValue"></textarea>
</label>

<h3>&lt;textarea&gt; with bindable autosize </h3>
<mat-checkbox [(ngModel)]="textareaAutosizeEnabled" name="autosizeEnabledCheckbox">
Autosize enabled
</mat-checkbox>
<textarea [cdkTextareaAutosize]="textareaAutosizeEnabled"></textarea>
</mat-card-content>
</mat-card>

Expand Down
1 change: 1 addition & 0 deletions src/demo-app/input/input-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export class InputDemo {
hideRequiredMarker: boolean;
ctrlDisabled = false;
textareaNgModelValue: string;
textareaAutosizeEnabled = false;
placeholderTestControl = new FormControl('', Validators.required);

name: string;
Expand Down
8 changes: 8 additions & 0 deletions src/lib/input/autosize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,12 @@ export class MatTextareaAutosize extends CdkTextareaAutosize {
@Input()
get matAutosizeMaxRows(): number { return this.maxRows; }
set matAutosizeMaxRows(value: number) { this.maxRows = value; }

@Input('mat-autosize')
get matAutosize(): boolean { return this.enabled; }
set matAutosize(value: boolean) { this.enabled = value; }

@Input()
get matTextareaAutosize(): boolean { return this.enabled; }
set matTextareaAutosize(value: boolean) { this.enabled = value; }
}

0 comments on commit 3915e08

Please sign in to comment.