2
votes

I have an array of Tour which is initialized with remote data by an API in the component.

tours: Tour[] = [];
filteredOptions: Observable<Tour[]>;

constructor(
  private api: APIService,
) { }

ngOnInit() {
  this.api.getTours().subscribe(
   data => { this.tours = data; this.filteredOptions = of(data); }
  );
}

These tours will be displayed in a mat input with autocomplete feature

<mat-form-field class="long tour-sel">
   <input matInput type="text" [formControl]="myControl" [matAutocomplete]="tourList" placeholder="Select a tour"/>
</mat-form-field>
<mat-autocomplete #tourList="matAutocomplete">
   <mat-option *ngFor="let tour of filteredOptions | async" [value]="tour">{{tour.name}}</mat-option>
</mat-autocomplete>

In the component this is the simple code that listening for change and filter the options

this.filteredOptions = this.myControl.valueChanges.pipe(
  startWith(''),
  map(value => this._filterTour(value))
);
private _filterTour(value: string): Tour[] {
   const filterValue = value.toLowerCase();
   return this.tours.filter(option => option.name.toLowerCase().includes(filterValue));
}

If I initialize the filteredOptions array in the subscribe function as I showed above , I see all the options in the autocomplete panel when I click the input but when I starting to type nothing change and the result are not filtered (the filter function is not called). If I delete this.filteredOptions = of(data); when I click on the input I do not see any options but filtering works and when i delete what I typed in the input all the options are viewed. I would like to see all the option on the first focus of the input without shatter the filtering feature.

1

1 Answers

5
votes

Possible solution:

ngOnInit() {
  this.api.getTours().subscribe(
   data => { 
       this.tours = data;
       this.filteredOptions = this.myControl.valueChanges.pipe(
           startWith(''),
           map(value => this._filterTour(value))
       );
  });
}

When filteredOptions is initialized (this.filteredOptions = of(data);) in the subscribe function, it overrides any of its previous references (reference to valueChanges.pipe), then async pipe subscribe to this new reference and the autocomplete is set to this static list and hence, filtering doesn't work.

However, if we don't initialize it in the subscribe function, this.tours is empty when valueChanges.pipe(startWith('')) is called and hence the list is empty to begin with.

So, the solution could be to initialize the filteredOptions with valueChanges.pipe() after 'this.tours' have been populated (i.e. inside subscribe function).