[Fixed] Dropdown value patch based on cursor position in textarea

Issue

I have a textarea and a dropdown. When I select a value in the dropdown
the particular value will appear or get inserted or added to the text area . So after typing dear if a user selects
a dropdown value called name it should appear as a dear name in the text area. I have done it but there is a bug

The dropdown value gets patched based on the maximum postion the cursor went instead
of the current cursor position. say for example you type three words and you place the cursor
near the first word and select a dropdown value the value gets patched on the en of third word(maximum position) instead
of the current cursor position
I want the dropdown value to be patched on current cursor position

HTML:

<textarea [(ngModel)]='textValue' rows="10" cols="70">
</textarea>
<div>
  <mat-form-field class="input-style">
    <mat-select (change)="changeValue($event)">
      <mat-option *ngFor="let li of list4" [value]="li">
        {{li}}
      </mat-option>
    </mat-select>
  </mat-form-field>
</div>

Ts:

changeValue(ev) {
this.textValue += ` ${ev.value}`; }

Kindly help if you guys know

Stackblitz: https://stackblitz.com/edit/angular-mat-form-field-rjr5tu?file=app%2Fform-field-prefix-suffix-example.html

Solution

you need take account the "selectionStart" and selectionEnd of the textArea. For this, create a template reference variable and pass to the function

<!--see the #text-->
<textarea #text [(ngModel)]='textValue' rows="10" cols="70">
</textarea>
...
    <!--pass the "variable" to the function changeValue-->
    <mat-select (change)="changeValue($event,text)">
      ...
    </mat-select>

Then your function changeValue

  changeValue(ev,textArea:any) {
    const posInitial=textArea.selectionStart;
    const posFinal=textArea.selectionEnd;
    this.textValue = this.textValue.substr(0,posInitial)+
                     ev.value+
                     this.textValue.substr(posFinal);
  }

NOTE: If you don’t want pass the "text" to the function you can also use ViewChild

@ViewChild("text") textArea:ElementRef

And to get the positions using

const posInitial=this.textArea.nativeElement.selectionStart;
const posFinal=this.textArea.nativeElement.selectionEnd;

See that in this case you use this.textArea.ElementRef

stackblitz

Leave a Reply

(*) Required, Your email will not be published