Linpter
Linpter

Reputation: 201

Angular Material: autocomplete with custom filter error

I started to use Material modules for Angular yesterday, specially to create an autocomplete input field with a custom filter: https://material.angular.io/components/autocomplete/overview

I'm still very new to Angular, I applied to the letter the example given on their website for my project, and even when just copying/pasting their example alone on a new project, I get the same errors which are:

input-form.component.ts(75,9): error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'Observable string'

AND

input-form.component.ts(76,9): error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'Observable<{}>'

The error reside in the ts file, with this : "filteredCities = this.cityControl..." in the ngOnInit. (see below)

But I don't really understand what means the error. Sorry if it may be a noobish question. Still I haven't found an answer on internet. What I am missing ? I'm very interested in understanding the issue.

Here are my files : input-form.component.html

<form [formGroup]="reportDataForm" (ngSubmit)="onSubmit()">
  <h3>Informations de l'en-tête</h3>
    <div class="form-group row">
      <label for="InputCity" class="col-3 col-form-label">Commune</label>
        <div class="search col-9">
          <mat-form-field>
            <input
            type="text"
            class="form-control"
            id="InputCity"
            matInput [formControl]="cityControl"
            [matAutocomplete]="auto"
            (click)="displayCities()">
          </mat-form-field>

          <mat-autocomplete #auto="matAutocomplete">
            <mat-option *ngFor="let city of filteredCities | async" [value]="city">
              {{ city }}
            </mat-option>
          </mat-autocomplete>
        </div>
       </div>
     </form>

and my ts file :

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

import {Subject} from 'rxjs/Subject';
import {Observable} from 'rxjs/Observable';
import {startWith} from 'rxjs/operator/startWith';
import {map} from 'rxjs/operator/map';

import { City } from '../../city';
import {CitiesService} from '../../data/cities.service';

@Component({
  selector: 'app-input-form',
  templateUrl: './input-form.component.html',
  styleUrls: ['./input-form.component.css']
})
export class InputFormComponent implements OnInit {
  toggle = false;
  reportDataForm: FormGroup;
  participantDataForm: FormGroup;
  citiesListInput: string[];

  cityControl: FormControl = new FormControl();
  filteredCities: Observable<string[]>;

  constructor(private citiesSvc: CitiesService) { }

  ngOnInit() {
    // Create an object that contains the data from the form and control the input
    this.reportDataForm = new FormGroup({
        'city': new FormControl(null, [Validators.required]),
    });   

    this.filteredCities = this.cityControl.valueChanges
      .pipe(
        startWith(''),
        map(val => this.filter(val))
      );
  }

  displayCities() {
    this.citiesListInput = this.citiesSvc.citiesList;
  }

  filter(val: string): string[] {
    return this.citiesSvc.citiesList.filter(city =>
      city.toUpperCase().indexOf(val.toUpperCase()) === 0);
  }

And here is my service which later will connect to a db. For now it just holds a list :

import {Injectable} from '@angular/core';

@Injectable()
export class CitiesService {

  citiesList = ['AFFOUX', 'LYON', 'DARDILLY', 'ATOOINE', 'AMELOTT'];

}

Versions:

 "typescript": "~2.4.2"
 "rxjs": "^5.5.2"

Upvotes: 0

Views: 1863

Answers (2)

Linpter
Linpter

Reputation: 201

I found the issue. There was an error in my imports of map and startWith. I used the auto import from IDE Webstorm and it was wrong.

So instead of

import {startWith} from 'rxjs/operator/startWith';
import {map} from 'rxjs/operator/map';

You have to use

import {startWith} from 'rxjs/operators/startWith';

import {map} from 'rxjs/operators/map';

Yep it was just missing a "s" at operator, it was as stu...simple as that.

Upvotes: 5

Arnaf
Arnaf

Reputation: 587

I'm afraid your city list didn't get data from service. Modify this method

 displayCities() {
    this.citiesListInput = this.citiesSvc.getCity();
  }

And in service I hope there is a city list you wanted to access from component. To do this add this method in your service

getCity(){
   return this.cityList;
}

Also you have to check if val is present in filter method

  filter(val: string): string[] {
      return val ? this.citiesListInput.filter(s => s.toLowerCase().indexOf(val.toLowerCase()) > -1)
      : this.citiesListInput;
  }

Here is a working demo https://stackblitz.com/edit/angular-qzmjse

Upvotes: 0

Related Questions