Expand input width dynamically to the length of string

时光总嘲笑我的痴心妄想 提交于 2019-12-04 10:09:02

You can use ngStyle to bind width of the mat-form-field to a calculated value, and use the input event on the input to set that value. For example, here's an input who's width follows the text width over 64px:

<mat-form-field [ngStyle]="{'width.px': width}">
    <input #elasticInput matInput (input)="resize()">
</mat-form-field>
<span #hiddenText style="visibility: hidden; white-space: pre;">{{elasticInput.value}}</span>

export class InputTextWidthExample {

    @ViewChild('hiddenText') textEl: ElementRef;

    minWidth: number = 64;
    width: number = this.minWidth;

    resize() {
        setTimeout(() => this.width = Math.max(this.minWidth, this.textEl.nativeElement.offsetWidth));
    }
}

Obviously, this example uses a hidden span element for getting the text width, which is a little hacky. There is surely more than one way to calculate a string's width, including this.

Here is the example on Stackblitz.

I now created a more suitable solution for this problem. After I found a perfect solution in jQuery and @Obsidian added the corresponding JS code. I tried to adapt it for Angular input and came up with the following. I also added some scenarios that support cutting and pasting strings.

Here is a demo on StackBlitz and the corresponding code:

Template:

<style>
    #invisibleTextID {
      white-space: pre;
    }

    // prevents flickering:
    ::ng-deep .mat-form-field-flex {
      width: 102% !important;
    }
</style>

<mat-form-field
  #formFieldInput
  [ngStyle]="{'width.px': width}">

  <input
    #inputText
    id="inputTextID"
    matInput
    [(ngModel)]="inString"
    (paste)="resizeInput()"
    (cut)="resizeInput()"
    (input)="resizeInput()">

</mat-form-field>

<span #invisibleText id="invisibleTextID">{{ inString }}</span>

Resize method:

@ViewChild('invisibleText') invTextER: ElementRef;

inString: string = '';
width: number = 64;

resizeInput() {

    // without setTimeout the width gets updated to the previous length
    setTimeout ( () =>{

      const minWidth = 64;

      if (this.invTextER.nativeElement.offsetWidth > minWidth) {
        this.width = this.invTextER.nativeElement.offsetWidth + 2;
      } else {
        this.width = minWidth;
      }

    }, 0)
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!