autocomplete suggestion in an input as gray letters after the cursor, not as a select popup

3.1k Views Asked by At

I use angular 10 with angular material to build my website.

I want to add input suggestions to matInput but in a different way that matAutocomplete does.. i don't want to show a list, I want to show one suggestion to a word that the user is already typing inside the input as gray letters after the last character that is typed and if presses tab it will autocomplete the word.

example..

lets say I want to write the word beverage and I started typing only 'beve'

so the input will show beve|rage the | character is the position of the cursor, and it will show rage in gray and the user can't really move forward cause it's not really part of the input, but if he clicks type it actually added the missing laters to the word and moves the cursor after the position of the full word.

I don't even know how to to start searching for how to implement such a thing, because whenever i search the terms autocomplete or suggestion it all goes show tutorials on autocomplete list which is not what I want.

I tried to play with matInput and mat-form-field a bit and like a good solution would be if I could show the placeholder even after the user typed something cause it looks like it has the same effect more or less of what I need.

so if I create this:

<mat-form-field>
  <mat-label>hello</mat-label>
  <mat-hint>test</mat-hint>
    <input matInput placeholder="foooooooo"/>
</mat-form-field>
 

so when I focus on the input element, i see foooooooo in gray but when I start typing the placeholder is gone. if the placeholder could still be shown then I could manipulate the placeholder dynamically, I could change on keypress even when the user clicks tab in order to complete the actual word in the input and move the cursor forward.

still don't know how to leave the placeholder! so if anyone got any idea how to do that.. or any other method to support what I need it would be great. thanks

2

There are 2 best solutions below

0
On BEST ANSWER

Edit:

A relatively easier solution would be to have two input elements overlapping each other, i.e they should be placed at the same position, having same width, height. And then make the backgroud-color transparent for both or the top element and set z-index of the actual input element to some large value -

// actual input element
<input type="text" [(ngModel)]="value" (input)="inputChange()" (keydown.tab)="tabKeyPressed()"/>
// below one is used to fake a placeholder
// placeholderValue = value + suggestion (calculated using inputChange() method
<input type="text" class="autocomplete" disabled  [(ngModel)]="placeholderValue" />

Please checkout this StackBlitz sample.

Solution 2

You can take help of this answer which suggests having a wrapper div and manipulate the data-placeholder attribute.

Solution 3 -

  1. You can have a separate input element (call it B).
  2. This secondary element B overlaps your actual input element (call it A) starting right after the entered text in A.
  3. To know B's starting position, have a hidden div (call it C) which contains exact value present in input element A.
  4. Then on every keyup event, find the suggestions based on the input and replace the placeholder property in B.
  5. On a tab event, replaced the input value in A if a suggestion exists.
    enter image description here

Below is how the html should look -

<div id="app">
  // A
  <input type="text" name="email" class="custom-input" (blur)="clearPlaceholder()" [(ngModel)]="textInput" (keyup)="autoSuggest()" (keydown.tab)="fillAutocomplete()" />
  <div class="clearit virtual-text" >
    // C
    <div class='hidden-text'>{{ textInput }}</div>
    // B
    <input type="text" class="autocomplete" [placeholder]="autoCompPlaceholder"/>
  </div>
  {{autoCompPlaceholder}}
</div>

Please take a look at this working StackBlitz example and also check out this article from where it's borrowed.

0
On

One way of implementing would be

<div>
<input type='text' id='inText' (keyup)='lookupValues($event)'>
<span style='color:grey'>{{suggestion}}</span>
</div>

in the ts file

lookupValues(event){
  // some logic 
this.suggestion = "suggested value"
}