24

I am working on angular2 applciation. i have a requirement to autosize textarea. I am trying to reuse the angular2-autosize from https://github.com/stevepapa/angular2-autosize

Followed the readme, But I am getting the below error

Uncaught Error: Module build failed: Error: ENOENT: no such file or directory, open 'C:\Users\Vipin\SampleApp\node_modules\angular2-autosize\angular2-autosize.js'.

Please suggest how to overcome this issue.

vipin
  • 245
  • 1
  • 2
  • 8
  • 1
    If by chance you are using Angular Material, here is a great solution: https://stackoverflow.com/a/50459162/3310669 – Jamneck Aug 07 '18 at 12:39

11 Answers11

36

The requested behaviour is already implemented in angular material as documented here: Angular Material Input Autosize. This is especially useful if you are using angular material anyways.

Just use cdkTextareaAutosize as in the example:

<textarea cdkTextareaAutosize></textarea>
Jens
  • 2,592
  • 2
  • 21
  • 41
25

Update (15.04.2018) Managed to package it, now its available as

npm install ngx-autosize

https://github.com/chrum/ngx-autosize

Old answer:

I had the same problem today and got it fixed! Please check my fork: https://github.com/chrum/angular2-autosize

Until PR is merged try:

npm install https://github.com/chrum/angular2-autosize.git --save

And then in your code, because it's slightly different, you just import module not directive...

so instead of:

import {Autosize} from 'angular2-autosize';

@NgModule({
  ...
  declarations: [
    Autosize
  ]
  ...
})

you should have:

import {AutosizeModule} from 'angular2-autosize';

@NgModule({
  ...
  imports: [
    AutosizeModule
  ]
  ...
})
chrystian
  • 831
  • 7
  • 15
16

you can do like this without using the package. its simple

in controller like below

autogrow(){
  let  textArea = document.getElementById("textarea")       
  textArea.style.overflow = 'hidden';
  textArea.style.height = '0px';
  textArea.style.height = textArea.scrollHeight + 'px';
}

and in html like below

<textarea id="textarea" (keyup)="autogrow()" ></textarea>
tanveer ahmad dar
  • 3,312
  • 1
  • 27
  • 29
  • 9
    Although this works, it breaks Angular's philosophy (ie do NOT directly manipulate the DOM). Rather than use document.getElementById, use @ViewChild to get a ref to the textarea (since it is after all a child of the component) – rmcsharry Oct 09 '17 at 14:20
  • 1
    Good Idea, but the view gets ugly when doing lots of height = 0px then increase, specially in text area with more lines than the entire viewport. – NaN Apr 11 '18 at 13:47
  • Resetting the height to 0px is not necessary, and can be done in more smart ways – Mohammad Kermani Oct 08 '19 at 11:47
  • 1
    And what are those smart ways? – vighnesh153 May 28 '20 at 12:35
  • 1
    Yes, we still do not know what the smarter ways are ^^ – Pierre Oct 20 '20 at 02:51
10

Why you need plugins for this, it's as simple as :

<textarea (keyup)="autoGrowTextZone($event)"></textarea>

and

autoGrowTextZone(e) {
  e.target.style.height = "0px";
  e.target.style.height = (e.target.scrollHeight + 25)+"px";
}
Chtioui Malek
  • 11,197
  • 1
  • 72
  • 69
7

Slightly modified answer for tanveer's answer would be to use @ViewChild

@ViewChild('textArea', { read: ElementRef }) textArea: ElementRef;

public autoGrow() {
 const textArea = this.textArea.nativeElement;
 textArea.style.overflow = 'hidden';
 textArea.style.height = '0px';
 textArea.style.height = textArea.scrollHeight + 'px';
}

And in the HTML it would be

<textarea (keyup)="autoGrow()" #textArea></textare>
dilantha111
  • 1,388
  • 1
  • 17
  • 19
  • As MohammadKermani commented on Tanveer's answer, "Resetting the height to 0px is not necessary, and can be done in more smart ways" – Patrick Apr 03 '20 at 04:48
  • 1
    If you have more then one textarea elements: @ViewChild('textArea1', { read: ElementRef }) textArea1: ElementRef; @ViewChild('textArea2', { read: ElementRef }) textArea2: ElementRef; public autoGrow(name) { const textArea = this[name].nativeElement; textArea.style.overflow = 'hidden'; textArea.style.height = '0px'; textArea.style.height = textArea.scrollHeight - 20 + 'px'; } – Ziv Barber Sep 16 '20 at 16:55
6

The solution that worked for me on IE as well as in the other browser

// Usage example: <textarea autoresize></textarea>

import { ElementRef, HostListener, Directive} from '@angular/core';

@Directive({
    selector: 'textarea[autosize]'
})

export class Autosize {
 @HostListener('input',['$event.target'])
  onInput(textArea: HTMLTextAreaElement): void {
    this.adjust();
  }
  constructor(public element: ElementRef){
  }
  ngAfterContentChecked(): void{
    this.adjust();
  }
  adjust(): void{
    this.element.nativeElement.style.overflow = 'hidden';
    this.element.nativeElement.style.height = 'auto';
    this.element.nativeElement.style.height = this.element.nativeElement.scrollHeight + "px";
  }
}

Add the below code to the APp.Module.ts

@NgModule({
  declarations: [
    Autosize
  ]
})

Use the tag on the HTML

 <textarea autosize></textarea>
San Jaisy
  • 15,327
  • 34
  • 171
  • 290
5

Simply

You can use as below:

<textarea [rows]="text.split('\n').length || 2">{{text}}</textarea>

or

create a function in ts :

  getHeight(content) {
    const v1 = Math.floor(content.length / 50);
    const v2 = content.split('\n').length;
    return Math.max(v1,v2)
  }

HTML:

<textarea [rows]="getHeight(text) || 2">{{text}}</textarea>
ahmad pirzargar
  • 129
  • 3
  • 7
3

Create the directive from angular-cli and add following code

import { Directive, ElementRef, HostListener, Input } from '@angular/core';

@Directive({
selector: '[appAutoGrow]'
})
export class AutoGrowDirective {

constructor(public element: ElementRef) {
}
@Input() maximumHeight: number; // based on pixel
@Input() minHeight: number; // based on pixel
@HostListener('input', ['$event.target'])
@HostListener('cut', ['$event.target'])
@HostListener('paste', ['$event.target'])
@HostListener('change', ['$event.target'])

ngOnInit(): void {
    this.adjustCustom();
}

adjustCustom(): void {
    const element = this.element.nativeElement;
    element.style.height = this.minHeight + 'px';
    element.style.height = (element.scrollHeight) + 'px';
    if (element.scrollHeight <= this.maximumHeight) {

        element.style.overflowY = 'hidden'
        delete element.style.maxHeight
    } else {

        element.style.overflowY = 'scroll'
        element.style.maxHeight = this.maximumHeight + 'px';
    }

}
}

and use the directive as follows

<textarea autofocus [maximumHeight]="200" [minHeight]="43" appAutoGrow></textarea>
1

I know the topic is quite old but I just change tanveer's answer to enter maximum Height as well.

    import { Directive, ElementRef, OnInit, HostListener, Input } from '@angular/core';

@Directive({
  selector: '[appAutoResize]',

})
export class AutoResizeDirective implements OnInit {
  constructor(public element: ElementRef) {
  }
  @Input() maximumHeight: number; // based on pixel
  @HostListener('input', ['$event.target'])
  ngOnInit(): void {
    this.adjust();
  }

  adjust(): void {
    const ta = this.element.nativeElement;
    const maxHeghit = this.maximumHeight;
    ta.style.overflow = 'hidden';
    ta.style.height = 'auto';
    if (ta.scrollHeight <= maxHeghit) { // while current height is less than maximumHeight
      ta.style.height = ta.scrollHeight + 'px';
    } else { // greater than maximumHeight
      ta.style.height = maxHeghit + 'px';
      ta.style.overflow = 'auto';
    }
  }

}

So, you will have control on the style behavior.
I hope it can help.

0

Here is the implementation of autosize in a directive which you can reuse on any textarea in your project.

import { Directive, Input, HostBinding } from '@angular/core';

@Directive({
    selector: 'textarea[autosize]'
})

export class TextareaAutosizeDirective {

    private _ngModel: any;

    public get ngModel(): any {
        return this._ngModel;
    }

    @Input()
    public set ngModel(value: any) {
        if (this._ngModel !== value) {
            this._ngModel = value;
            this.resize();
        }
    }

    @HostBinding('rows')
    public rows: number;

    @Input()
    public minRows: number = 1;

    constructor() {}

    private resize() {
        this.rows = !this._ngModel ? this.minRows : this.ngModel.split('\n').length;
    }

}

You can use it in a following way:

<textarea autosize minRows="2" [(ngModel)]="property"></textarea>

By adding autosize textarea becomes automatically resized. You can also specify minimum number of rows which textarea has.

michal.jakubeczy
  • 8,221
  • 1
  • 59
  • 63
0

I am a bit late but let me provide my answer as well. Just simply follow the following

  adjustTextareaHeight() {
    const textarea: HTMLTextAreaElement = document.querySelector('textarea');
    textarea.style.height = 'auto';
    textarea.style.height = `${textarea.scrollHeight}px`;
  }
<textarea (input)="adjustTextareaHeight()"></textarea>