Baruch Mashasha
Baruch Mashasha

Reputation: 979

Angular Material autocomplete From API

I tried to use auto-complete from an API but it did not work. its works only when I use it with no API as hardcoded.

this is my Component TS: inside there, There is a callback method with the data from the API (onGetTaxList)

import { Component, OnInit } from '@angular/core';
import { UsersService } from '../../../../core/services/users.service';
import { FormControl } from '@angular/forms';
import { Observable } from 'rxjs';
import { map, startWith } from 'rxjs/operators';

@Component({
  selector: 'app-create-process-modal',
  templateUrl: './create-process-modal.component.html',
  styleUrls: ['./create-process-modal.component.sass']
})
export class CreateProcessComponent implements OnInit {
  myControl = new FormControl();
  options = [
    { name: 'One' },
    { name: 'Two' },
    { name: 'Tree' },
  ];
  filteredOptions: Observable<any>;


  constructor(private service: UsersService) { }

  ngOnInit() {
    this.service.createNewProcess((data) => this.onGetTaxList(data));
    this.filteredOptions = this.myControl.valueChanges
      .pipe(
        startWith(''),
        map(value => this._filter(value))
      );
  }

  onGetTaxList(data) {
    console.log(data);
  }
  private _filter(value: string) {
    const filterValue = value.toLowerCase();

    return this.options.filter(option => option.name.toLowerCase().includes(filterValue));
  }
}

Component html:

<div class="formContainer">
    <h2 style="text-align: right">New Process</h2>
    <mat-form-field style="text-align: right">
        <input type="text" placeholder="Start Typing..." matInput [formControl]="myControl" [matAutocomplete]="auto">
        <mat-autocomplete #auto="matAutocomplete">
                <mat-option *ngFor="let option of filteredOptions | async" [value]="option.name">
                  {{option.name}}
                </mat-option>
              </mat-autocomplete>
    </mat-form-field>

</div>

In this state its work with the object

options = [
        { name: 'One' },
        { name: 'Two' },
        { name: 'Tree' },
      ];

and now i want to make it works from the data api:

0: {companyName: "ziro", cid: "524023240", partners: Array(4)}
1: {companyName: "plus", cid: "524023240", partners: Array(2)}

and I need the autocomplete will filter the companyName. Thanks.

Upvotes: 23

Views: 44303

Answers (6)

Shashwat Gupta
Shashwat Gupta

Reputation: 5264

html

 <input class="hscode-box" placeholder=" Select HS Code" type="text" matInput [formControl]="hscodeControl"
        [matAutocomplete]="auto">
      <mat-autocomplete #auto="matAutocomplete">
        <mat-option *ngFor="let option of hscodeOptions | async" [value]="option.code">
          {{option.code}}
        </mat-option>
      </mat-autocomplete>


.ts

 ngOnInit() {
   
    this.hscodeOptions = this.hscodeControl.valueChanges.pipe(
      startWith(''),
      debounceTime(500),
      switchMap((value) => {
        console.log(value, "value");
        return  this.hscodes(value);
      }),
    );


 hscodes(hscode) {
      return this._ProductService.getHSCodeList(hscode).pipe(
        filter(data => !!data),
        map((data) => {
          return data
        })
      )
          }

Upvotes: 0

corsaro
corsaro

Reputation: 773

the best way from call data whit out charge all data but partial data on server side: the call start from first letter

Component no Async

<form class="example-form">
    <mat-form-field class="example-full-width">
      <input type="text" placeholder="Pick one" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto">
      <mat-autocomplete #auto="matAutocomplete">
        <mat-option *ngFor="let option of filteredOptions" [value]="option.name">
          {{option.name}}
        </mat-option>
      </mat-autocomplete>
    </mat-form-field>
  </form>

.ts File

ngOnInit() {
    this.myControl.valueChanges
      .subscribe(value => {
        if(value.length >= 1){
          this.dashboardService.getProductsByName(value).subscribe(response => {
            this.filteredOptions = response;
          });
        }
        else {
          return null;
        }
      })
}

Upvotes: 6

Savaj Patel
Savaj Patel

Reputation: 535

Component:

  constructor(private service: Service) { 
  this.filteredOptions = this.myControl.valueChanges
        .pipe(
          startWith(''),
          debounceTime(400),
          distinctUntilChanged(),
          switchMap(val => {
            return this.filter(val || '')
          })       
        );
  }

  // filter and return the values
 filter(val: string): Observable<any[]> {
    // call the service which makes the http-request
    return this.service.getData()
     .pipe(
       map(response => response.filter(option => { 
         return option.name.toLowerCase().indexOf(val.toLowerCase()) === 0
       }))
     )
   }  
}

Service:

opts = [];

getData() {
  return this.opts.length ?
    of(this.opts) :
    this.http.get<any>('https://jsonplaceholder.typicode.com/users').pipe(tap(data => this.opts = data))
}

For check full demo check this link Stackblitz

Upvotes: 22

AVJT82
AVJT82

Reputation: 73337

I see no attempt to even get the data from Api, so first of all you should add that. Then you are trying to filter by name, which does not exist in your data, you want to filter by companyName, then use that. All in all, change your code to:

this.filteredOptions = this.myControl.valueChanges
  .pipe(
    startWith(''),
    switchMap(value => this._filter(value))
  );

And the function to filter and getting the data from api:

private _filter(value: string) {
  const filterValue = value.toLowerCase();
  // add your service function here
  return this.service.getData().pipe(
    filter(data => !!data),
    map((data) => {
      return data.filter(option => option.companyName.toLowerCase().includes(value))
    })
  )
}

DEMO: StackBlitz

Upvotes: 3

amir_barak
amir_barak

Reputation: 94

on your ngOnInit try to add this:

ngOnInit() {
   .
   ..
   ...
   this.options = []; //init the options data.
   this.yourService.getAllCompaniesOrSomething.subscribe((all_companies)=>{
      this.options = all_companies.map((company)=>{ 
                          return {
                                    name:company.companyName
                          } 
                      });//closing the map function.
   });//closing the subscription.
}

Upvotes: 1

Baruch Mashasha
Baruch Mashasha

Reputation: 979

Solved:

    import { Component, OnInit } from '@angular/core';
    import { UsersService } from '../../../../core/services/users.service';
    import { FormControl } from '@angular/forms';
    import { Observable } from 'rxjs';
    import { map, startWith } from 'rxjs/operators';
    import { MatAutocompleteSelectedEvent } from '@angular/material';

    @Component({
      selector: 'app-create-process-modal',
      templateUrl: './create-process-modal.component.html',
      styleUrls: ['./create-process-modal.component.sass']
    })
    export class CreateProcessComponent implements OnInit {
      myControl = new FormControl();
      options;
      filteredOptions: Observable<any>;


      constructor(private service: UsersService) { }

      ngOnInit() {
        this.service.createNewProcess((data) => this.onGetTaxList(data));
      }

      // Auth Complete
      onGetTaxList(data) {
        this.options = data;
        this.filteredOptions = this.myControl.valueChanges
          .pipe(
            startWith(''),
            map(value => value.length >= 1 ? this._filter(value) : [])
          );
      }
      private _filter(value: string) {
        const filterValue = value.toLowerCase();

        return this.options.filter(option => option.companyName.toLowerCase().includes(filterValue));
      }
}

Html:

<div class="formContainer">
    <h2 style="text-align: right">New Process</h2>
    <mat-form-field style="text-align: right">
        <input type="text" placeholder="Start Typing..." matInput [formControl]="myControl" [matAutocomplete]="auto">
        <mat-autocomplete #auto="matAutocomplete">
                <mat-option *ngFor="let option of filteredOptions | async" [value]="option.companyName">
                  {{option.companyName}}
                </mat-option>
              </mat-autocomplete>
    </mat-form-field>

</div>

Upvotes: 0

Related Questions