2

I have a custom directive to adjust the ion-textarea height to autosize the height as text is entered rather than setting a fixed row height or having ugly scroll bars as the textarea fills up.

In Ionic-4 I am unable to get the nativeElement of the html textarea of the ion-textarea. Any help would be great

It's running on Angular 6 and Ionic 4 but when I try and get this.element.nativeElement.getElementsByTagName('textarea')[0] it is always undefined so I can't set the height programatically.

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

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

export class AutosizeDirective implements OnInit {
  @HostListener('input', ['$event.target'])
  onInput(textArea:HTMLTextAreaElement):void {
    this.adjust();
  }

  constructor(public element:ElementRef) {
  }

  ngOnInit():void {
    setTimeout(() => this.adjust(), 0);
  }

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

As the const textArea always comes back undefined I can't set the height to follow the scroll height to prevent the scroll bars.

Anyone been able to do this in Ionic-4? seen working examples in Ionic-3 as per the above code.

Thank you Rowie

Rowie
  • 243
  • 5
  • 17
  • so this method here: getElementsByTagName() requires this directive to be used then on proper DOM elements. Which html elements or components (if custom) you are applying this directive on? Ionic 4's big change is move from angular components to ionic web components. So to triage this problem ideally please share which ionic 3 component you used this directive on and it worked vs ionic 4 – Sergey Rudenko Jan 13 '19 at 23:22
  • I am using this on Ionic 4 ion-textarea - so the TextArea component. I am brand new to Ionic so only done this on version 4 and have no example on version 3 to compare other than when I found this code it was working in an example online so I'm guessing it might have been version 3. The html is: – Rowie Jan 14 '19 at 07:04
  • I works sort of fine if I use a non ionic component and just normal html item e.g. But I am wanting the ionic component if possible – Rowie Jan 14 '19 at 07:06

2 Answers2

4

Below code would help your problem.

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

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

export class AutoSizeDirective implements AfterViewInit {
  readonly defaultHeight = 64;

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

  constructor(private element: ElementRef) {}

  ngAfterViewInit() {
    this.adjust();
  }

  adjust(textArea?: HTMLTextAreaElement) {
    textArea = textArea || this.element.nativeElement.querySelector('textarea');

    if (!textArea) {
      return;
    }

    textArea.style.overflow = 'hidden';
    textArea.style.height = 'auto';
    textArea.style.height = (textArea.value ? textArea.scrollHeight : defaultHeight) + 'px';
  }
}

Usage: <ion-textarea autosize></ion-textarea>

I have confirmed it on Ionic 4.0.2/Angular 7.2.6.

Regards.

coturiv
  • 2,880
  • 22
  • 39
  • Thank you for your update and provided code. Not sure what I am doing wrong but I just can't get that directive to fire using the ion-textarea. I have added a console.log in the directive and it never fires. I have even added ngOnInit and put a console.log in there and still nothing output. – Rowie Feb 22 '19 at 15:59
  • Please make sure that you have imported this directive to the page/component. – coturiv Feb 22 '19 at 16:11
  • I have added this to the xxx.module.ts file of the page @NgModule({ imports: [ AutoSizeDirective, but it comes up with a compile error: Error: Uncaught (in promise): Error: Unexpected value 'undefined' imported by the module – Rowie Feb 22 '19 at 16:21
  • Sorry, my bad, I just created a brand new ionic project, added your directive and declared it in a common module and added it to the default home page. Works just fine. Thank you for your solution - now I need to work out why my actual project just won't accept it. Thanks for all the help – Rowie Feb 24 '19 at 09:41
  • ok, now I am confused!!! In my blank new project the ion-textarea dom element simply has a textarea dom element inside it. However, in my actual project, my ion-textarea dom element has a shadow-dom style with the textarea dom element nested inside. I have no idea why a new project is nice and clean but my actual project has injected a shadow dom into the ion-textarea element. If anyone can shed any light on this ... – Rowie Feb 24 '19 at 10:27
  • ok, sorted! for anyone else out there having the same sort of issues. I thought I was on the latest ionic framework but I wasn't even though I kept doing the upgrade. I was on 4.0.0-rc.1. I have somehow managed to upgrade to 4.0.2 and indeed the shadown dom on the ion-textarea has now gone and the directive kindly supplied above works just fine! phew – Rowie Feb 24 '19 at 11:32
  • Do you know how to reset the textarea hight after it is cleared (textarea.value = "")? – ACES Mar 09 '19 at 20:07
  • I have the same issue ACES. to reset the height after I reset the value to "". No solution yet :-( – Rowie Mar 16 '19 at 09:48
  • I have just updated the answer, textarea default height is `64px`, so the solution is `textArea.style.height = (textArea.value ? textArea.scrollHeight : 64) + 'px'`. – coturiv Mar 17 '19 at 14:50
  • Thank you Coturiv for the addition. I think the problem is, the HostListener in the Directive is not fired when changing the value of the textbox to empty string via code. If I put a console.log inside the Adjust method: it fires on each keypress but when I set the value to "" in code on the page the adjust method is not fired so I can only assume the HostListener is only firing on keyboard type changes. Is there a listener for "any change" of the textarea value do you know of? – Rowie Mar 23 '19 at 11:06
2

this package does all the autosizing of my ion-textareas for me https://github.com/chrum/ngx-autosize just follow the guide and get it working, if it doesn't work importing it into the app.module.ts then try importing it into the page's module, I personally needed that dunno if you will, but package is a life saver

sandu
  • 66
  • 10