Reputation: 65
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
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