Patira
Patira

Reputation: 65

Angular 6 Material - Autocomplete with data from server

I need to fetch some data from a server and show it into the Material autocomplete.

The thing is that when you click in the input field, you can't have the results right away. You have to type something into the input field to get some results back.

I've forked and changed the autocomplete demo on Stackblitz, so you can see what I'm talking about. In this demo, I didn't actually fetch data from a server. I just mocked it with some setTimeout. But the behavior is pretty much the same.

HTML:

<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">
    <img style="vertical-align:middle;" aria-hidden src="{{state.flag}}" height="25" />
    <span>{{ state.name }}</span> |
    <small>Population: {{state.population}}</small>
  </mat-option>
</mat-autocomplete>

TS:

import {Component, OnInit} from '@angular/core';
import {FormControl} from '@angular/forms';

import {Observable} from 'rxjs';
import {map, startWith} from 'rxjs/operators';

export class State {
  constructor(public name: string, public population: string, public flag: string) { }
}

@Component({
  selector: 'autocomplete-overview-example',
  templateUrl: 'autocomplete-overview-example.html',
  styleUrls: ['autocomplete-overview-example.css']
})
export class AutocompleteOverviewExample implements OnInit {
  stateCtrl: FormControl;
  filteredStates: Observable<any[]>;

  states: State[];

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

  ngOnInit() {
    setTimeout(() => {
      return this.states  = [
    {
      name: 'Arkansas',
      population: '2.978M',
      // https://commons.wikimedia.org/wiki/File:Flag_of_Arkansas.svg
      flag: 'https://upload.wikimedia.org/wikipedia/commons/9/9d/Flag_of_Arkansas.svg'
    },
    {
      name: 'California',
      population: '39.14M',
      // https://commons.wikimedia.org/wiki/File:Flag_of_California.svg
      flag: 'https://upload.wikimedia.org/wikipedia/commons/0/01/Flag_of_California.svg'
    },
    {
      name: 'Florida',
      population: '20.27M',
      // https://commons.wikimedia.org/wiki/File:Flag_of_Florida.svg
      flag: 'https://upload.wikimedia.org/wikipedia/commons/f/f7/Flag_of_Florida.svg'
    },
    {
      name: 'Texas',
      population: '27.47M',
      // https://commons.wikimedia.org/wiki/File:Flag_of_Texas.svg
      flag: 'https://upload.wikimedia.org/wikipedia/commons/f/f7/Flag_of_Texas.svg'
    }
  ];
    }, 1000);
  }

  filterStates(name: string) {
    return this.states.filter(state =>
      state.name.toLowerCase().indexOf(name.toLowerCase()) === 0);
  }

}

P.S: I've done my searches and researches :) I've found results that are somewhat similar to my question, but the details are completely different and they are NOT what I'm looking for. So I had to ask this question separately.

Upvotes: 1

Views: 3289

Answers (1)

Anshuman Jaiswal
Anshuman Jaiswal

Reputation: 5462

Problem is with filteredStates initially you are not assigning any value in it. Check the modified code below:

constructor() {
    this.stateCtrl = new FormControl();
    this.stateCtrl.valueChanges.subscribe(val => {
      this.filterStates(val);
    });
}

ngOnInit() {
    this.states  = [
        {
          name: 'Arkansas',
          population: '2.978M',
          flag: 'https://upload.wikimedia.org/wikipedia/commons/9/9d/Flag_of_Arkansas.svg'
        },
        {
          name: 'California',
          population: '39.14M',
          flag: 'https://upload.wikimedia.org/wikipedia/commons/0/01/Flag_of_California.svg'
        },
        {
          name: 'Florida',
          population: '20.27M',
          flag: 'https://upload.wikimedia.org/wikipedia/commons/f/f7/Flag_of_Florida.svg'
        },
        {
          name: 'Texas',
          population: '27.47M',
          flag: 'https://upload.wikimedia.org/wikipedia/commons/f/f7/Flag_of_Texas.svg'
        }
    ];
    this.filteredStates = new Observable(observer => {
      setTimeout(() => {
          observer.next(this.states);
      }, 1000);
    });
}

filterStates(name: string) {
    let filteredData = this.states.filter(state =>
    state.name.toLowerCase().indexOf(name.toLowerCase()) === 0);
    this.filteredStates = new Observable(observer => {
        observer.next(filteredData);
    }); 
}

Upvotes: 1

Related Questions