angular 5 material 2 - auto complete getting data from external api

18,111

I see some issues, for example you should map(val => this.getArrayOfValue(val)). But I would also suggest some additional changes. Think about adding debounceTime, distinctUntilChanged and switchMap. Set a debounce time of your choosing. This, not to completely overload the api. As well as switchMap is useful to make the request switches to the last value user has typed. Also you should consider using a service for your api requests, that is usually how we handle things. So I suggest moving the http-request to the service and call that from the component.

TS:

  // inject your created service which makes the http-request
  constructor(private service: Service) { 

  this.filteredOptions = this.myControl.valueChanges
        .pipe(
          startWith(''),
          debounceTime(400),
          distinctUntilChanged(),
          switchMap(val => {
            return this.filter(val || '')
          })       
        );
  }

  // filter and return the values
 filter(val: string): Observable<any[]> {
    // call the service which makes the http-request
    return this.service.getData()
     .pipe(
       map(response => response.filter(option => { 
         return option.name.toLowerCase().indexOf(val.toLowerCase()) === 0
       }))
     )
   }  
}

Service would then call the http-request. If you do not overload the API, we could store the data in a variable after first fetch, and instead return an observable of that variable, but that is just optional.

opts = [];

getData() {
  return this.opts.length ?
    of(this.opts) :
    this.http.get<any>('https://jsonplaceholder.typicode.com/users').pipe(tap(data => this.opts = data))
}

Also you seem to use value for your option in template. If you want to capture the whole object, use [value].

Here's a DEMO for you to play around with :)

Share:
18,111
andre luis borges de paula
Author by

andre luis borges de paula

Updated on June 07, 2022

Comments

  • andre luis borges de paula
    andre luis borges de paula about 2 years

    I'm using angular 5 and material 2.

    In ts file, I have this proeperty:

          filteredOptions: Observable<any[]>;
    

    This property is going to have an array of values to show in the autocomplete field.

          [{
            id:'1', name: 'teste 1'},
            {id:'2', name: 'teste 2'},
            {id:'3', name: 'teste 3'
          }]
    

    This array of values come from the database and it is going to be shown after the user type something.

    html file:

              ##            <form class="example-form">
              ##              <mat-form-field class="example-full-width">
              ##                <input type="text" placeholder="Assignee" aria-label="Assignee" matInput [formControl]="myControl" [matAutocomplete]="auto">
              ##                <mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn">
              ##                  <mat-option *ngFor="let option of filteredOptions | async" [value]="option">
              ##                    {{ option.name }}
              ##                  </mat-option>
              ##                </mat-autocomplete>
              ##              </mat-form-field>
              ##            </form>
    

    ts file example:

        this.filteredOptions = Observable<any[]>;
    
        ngOnInit() {
          this.filteredOptions = this.myControl.valueChanges
            .pipe(
              startWith({}),
              map(getArrayOfValue(val))            
            );
          }
    
          // it is going to call an api to get the array of values to be shown in the field
          getArrayOfValue(val): Observable<any[]> {            
            const url = this.ROOT_URL + 'veiculo/' + val;
            return this.http.get<any[]>(url);
          }
    

    This code give me an error

    ERROR in src/app/oficina/cadastro/veiculo/veiculo.component.ts(55,5): error TS2322: Type 'Observable>' is not assignable to type 'Observable'. Type 'Observable' is not assignable to type 'any[]'. Property 'includes' is missing in type 'Observable'

  • Parth Godhani
    Parth Godhani almost 5 years
    ERROR TypeError: response.filter is not a function, i am using heremap geolocation api
  • eddyizm
    eddyizm over 3 years
    I'm trying to implement this in a service but not sure what stays in the calling ts component file and what gets moved to the service along with the search term.