[SOLVED] Ion-textarea resize height dynamically

Do someone have a great idea how to implement an ion-textarea which would be per default presented with 1 row but according what the user type could grow to max 3 rows?

Something like:

 <ion-textarea #msgInput rows="1" maxLength="500" (keyup)="resize()"></ion-textarea>

But the question is, what to add in the resize method to achieve the goal?

 @ViewChild('msgInput') msgInput: TextInput;
 
 resize() {
   // Something good, something bad? A bit of both!
 }
3 Likes

Freak, took me way to much tiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiime just for that, but got it.

The tricks is: don’t use ion-textarea but textarea and don’t forget the ‘.px’ part to change the height dynamically.

Html:

<textarea #myInput id="myInput" rows="1" maxLength="500" (keyup)="resize()" [(ngModel)]="myStuff"></textarea>

Css:

#myInput {
    width: calc(100% - 10px);
    border: 0;
    border-radius: 0;
    background: transparent;
}

Ts:

@ViewChild('myInput') myInput: ElementRef;

resize() {
    this.myInput.nativeElement.style.height = this.myInput.nativeElement.scrollHeight + 'px';
}
15 Likes

after following this solution , if i include placeholder , it comes as red colored , how to change it to default ?

And how to make it work with ion-textarea?

@Navil no idea, I only find a solution with textarea, but you are most welcomed to try and share you solution if you find it :wink:

@devanshsadhotra was probably a css issue, style.height chg the height not the color of the placeholder

Pretty sure, this is a bug from the ionic framework. I will try to find any workaround

got that fixed , by using text area instead of ion-textarea

1 Like

I found this solution:

<ion-item>
        <ion-label floating>Model</ion-label>
        <ion-textarea #myInput id="myInput" rows="1" maxLength="500" (keyup)="resize()" [(ngModel)]="model"></ion-textarea>
      </ion-item>

@ViewChild('myInput') myInput: ElementRef;
  resize() {
      var element = this.myInput['_elementRef'].nativeElement.getElementsByClassName("text-input")[0];
      var scrollHeight = element.scrollHeight;
      element.style.height = scrollHeight + 'px';
      this.myInput['_elementRef'].nativeElement.style.height = (scrollHeight + 16) + 'px';
  }
11 Likes

Could you give a solution with more detail? Because I’ve got error “[ts] Cannot find name ‘ElementRef’” for variable ‘ElementRef’?
.

I built on someone else’s code to make the following directive:

// An autoresize directive that works with ion-textarea
// Usage example: <ion-textarea autoresize></ion-textarea>
// Based on https://www.npmjs.com/package/angular2-autosize

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

@Directive({
  selector: "ion-textarea[autoresize]" // Attribute selector
})
export class TextareaAutoresize implements OnInit {

  @HostListener("input", ["$event.target"])
  onInput = (textArea: HTMLTextAreaElement): void => {
    this.adjust();
  }

  constructor(public element: ElementRef) { }

  ngOnInit(): void {
    const waitThenAdjust = (trial: number): void => {
      if (trial > 10) {
        // Give up.
        return;
      }

      const ta = this.element.nativeElement.querySelector("textarea");
      if (ta !== undefined && ta !== null) {
        this.adjust();
      }
      else {
        setTimeout(() => {
          waitThenAdjust(trial + 1);
        }, 0);
      }
    };

    // Wait for the textarea to properly exist in the DOM, then adjust it.
    waitThenAdjust(1)
  }

  adjust = (): void => {
    const ta = this.element.nativeElement.querySelector("textarea");
    if (ta !== undefined && ta !== null) {
      ta.style.overflow = "hidden";
      ta.style.height = "auto";
      ta.style.height = ta.scrollHeight + "px";
    }
  }

}
3 Likes

Your error should be resolved by importing ElementRef through the following statement:

import { Component, ViewChild, ElementRef } from '@angular/core';

Great job! Works well! One small addition, it’s also good to add minimum height, in case you have a wider text area, then it won’t just to line height to only later expand:

min-height: 40px;

2 Likes

this works great! thank you.

does anyone know how the make is smaller again if i were to delete rows of text? when i type it expands but when i delete the text it stays expanded. i want it to return back to original size.

1 Like

you can try setting height to ‘auto’

Thank you for shared this solution

heeeerrrrrrrrrr thanks for this code it really solved my problem
chop kiss bro

To make resizing work for deleting text, I added a line to the resize method that first sets the textarea height to auto, and then does the resize based on scroll height. This clears the height and then recomputes as the user types. Seems to work for me even when the delete button is held down, and does not seem to introduce any visual glitches. (I haven’t tested across devices, only on my iPhone). My revised method looks like this:

  resize() {
    this.myInput.nativeElement.style.height = 'auto'
    this.myInput.nativeElement.style.height = this.myInput.nativeElement.scrollHeight + 'px';
  }
4 Likes

Here is a great directive: :sunglasses:

https://competenepal.com/elastic-text-area-component-in-ionic-framework/

2 Likes

thank you!!
this worked. have to test it on devices first thought but int he browser testing so far so good.

I believe we should listen for only enter key event than every key stroke for more performance.

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

@Directive({
  selector: 'ion-textarea[autosize]' // Attribute selector,
})
export class AutosizeDirective {

  @HostListener('document:keydown.enter', ['$event']) onKeydownHandler(evt: KeyboardEvent) {
    this.adjust()
  }

  constructor(public element:ElementRef) {
  }

  ngAfterViewInit(){
    this.adjust()
  }

  adjust():void {
    let textArea = this.element.nativeElement.getElementsByTagName('textarea')[0];
    textArea.style.overflow = 'hidden';
    textArea.style.height = 'auto';
    textArea.style.height = (textArea.scrollHeight + 32) + "px";
  }

}

2 Likes