1
votes

I'm fighting with Material's Autocomplete for several days. I've used tons of examples from here, and still can't get it work. What I want to achieve is get Users from API, load them to autocomplete as the name should be visible but I want a value as object. This is what I've got till now:

***API Service:***

export class UserService {
  constructor(private httpClient: HttpClient) {}

  getData() {
    return this.httpClient.get<any>('https://jsonplaceholder.typicode.com/users');
  }
}

***component.ts***

constructor(private usc: BreweryService, private formBuilder: FormBuilder) { 
    this.users = this.usc.getData();
    
  }
  
  ngOnInit() {
    this.form = this.formBuilder.group({
      myControl: ['', Validators.required],
      name: ['', Validators.required]
    });
 
    this.filteredUsers = this.form.controls['myControl'].valueChanges.pipe(
      startWith(''),
      debounceTime(200),
      distinctUntilChanged(),
      switchMap(val => {
        return this.filter(val || '')
        
      })
    )    
}

filter(val: string) {
  return this.users.pipe(
    map(response => response.filter(option => {
      return option.name.toLowerCase().indexOf(val.toLowerCase()) === 0
    }))
  )
}

displayFn(user): string {
  return user.name;
}

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

The console throws error:

"ERROR TypeError: val.toLowerCase is not a function"

and autocomplete not working on typing.

I've created stackblitz to show the problem

1

1 Answers

0
votes

You need to do like this

  myControl = new FormControl();

After

this.filteredUsers = this.myControl.valueChanges.pipe(
  startWith(""),
  map(value => (typeof value === "string" ? value : value.name)),
  map(name => (name ? this.filter(name) : this.users.slice()))
);

Check if this.users is not empty and return list of object with name in

And be sure filteredUsers is Observable

filter(val: string) {
    const filterValue = name.toLowerCase();
    return this.users.filter(
      option => option.name.toLowerCase().indexOf(filterValue) === 0
    );
}

Hope useful