5
votes

I´m starting to use Material in one of my projects. Seeing the example of the <mat-autocomplete> of the documentation website...

<mat-form-field class="example-full-width">
  <input matInput placeholder="State" aria-label="State" [matAutocomplete]="auto" [formControl]="stateCtrl">
    <mat-autocomplete #auto="matAutocomplete">
    <mat-option *ngFor="let state of filteredStates | async" [value]="state.name">
    <span>{{state.name}}</span> |
  </mat-option>
</mat-autocomplete>

ts:

    export class AutocompleteOverviewExample {        
      stateCtrl = new FormControl();
      filteredStates: Observable<State[]>; 
      states: State[] = [
            { name: 'Arkansas'  },
            ...
            { name: 'Texas' }
          ];

          constructor() {
            this.filteredStates = this.stateCtrl.valueChanges
              .pipe(
                startWith(''),
                map(state => state ? this._filterStates(state) : this.states.slice())
              );
          }

          private _filterStates(value: string): State[] {
            const filterValue = value.toLowerCase();
            return this.states.filter(state => state.name.toLowerCase().indexOf(filterValue) === 0);

            // Material example, its basically a ._http.get(value).map
          }
        }

The <mat-option> list its deployed when you click in the input field. I would like to avoid that and only show the options when X (they have write 3 or more characters, its a 'small' list with 5 or 10 elements, etc).

How can I modify this behavior and do it dynamically?

2

2 Answers

8
votes

This is default behavior in the library. To customize it you can just hide the autocomplete options with CSS on change of model value of autocomplete & then set whatever the minimum length you want to have on input text & then accordingly show the autocomplete options. Update view code to:

<mat-form-field class="example-full-width">
  <input matInput placeholder="State" aria-label="State" [matAutocomplete]="auto" [formControl]="stateCtrl" 
  (ngModelChange)="updatedVal($event)">
  <mat-autocomplete #auto="matAutocomplete">
   <mat-option *ngFor="let state of filteredStates | async" [value]="state.name" 
    [ngClass]="{'hide-autocomplete': !showAutocomplete}">
   <span>{{state.name}}</span> |
   </mat-option>
  </mat-autocomplete>
</mat-form-field>

Here I've added ngModelChange on input filed to check model change. And on mat-option I've added ngClass. Where

.hide-autocomplete { display: none; }

And in class the updatedVal method is:

updatedVal(e) {
  if(e && e.length >= 3) {
     this.showAutocomplete = true;
  } else {
     this.showAutocomplete = false;
  }
}

So that hide class only be added to mat-option when input length is less than 3.

Demo Example

0
votes

I think this is much cleaner solution

<mat-form-field class="example-full-width">
   <!-- -->
   <input matInput #searchInput placeholder="State" aria-label="State" 
   [matAutocomplete]="auto" [formControl]="stateCtrl">
   <mat-autocomplete #auto="matAutocomplete">
   <!--put mat-option inside a div and test input length value to show mat-option --> 
   <div *ngIf="searchInput.value.length>3">
      <mat-option *ngFor="let state of filteredStates | async" 
      [value]="state.name">
         <span>{{state.name}}</span> |
      </mat-option>
   </div>
</mat-autocomplete>

putting mat-option inside div and showing the div only if the input value lenght greater then 3.