Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use angular material 6 autocomplete with data server

I'm developing a simple page with Angular 6 and Material 6. I want to recover data from a service using the autocomplete of Material, but I don´t know how to do it well.

From the official example https://material.angular.io/components/autocomplete/overview I don't understand how to use a service to integrate it with the autocomplete.

Can anybody help me?

Thanks

like image 355
macosta Avatar asked Jun 01 '18 22:06

macosta


2 Answers

Finally, I found a solution to what I wanted to do! To bind a FormArray to mat-table dataSource you have to: Briefly, the example is this:

<table mat-table [dataSource]="itemsDataSource">
  <ng-container matColumnDef="itemName">
    <td mat-cell *matCellDef="let element">{{ element.value.material?.name }}</td>
  </ng-container>
  <ng-container matColumnDef="itemCount">
    <td mat-cell *matCellDef="let element">{{ element.value.itemCount }}</td>
  </ng-container>
  <tr mat-row *matRowDef="let row; columns: itemColumns;"></tr>
</table>

and the code:

export class ItemListComponent implements OnInit {
  constructor(
    private fb: FormBuilder
  ) { }
  itemColumns = ['itemName', 'count'];
  itemForm: FormGroup;
  itemsDataSource = new MatTableDataSource();
  get itemsForm() {
    return this.itemForm.get('items') as FormArray;
  }
  newItem() {
    const a = this.fb.group({
      material: new FormControl(), //{ name:string }
      itemCount: new FormControl() // number 
    });
    this.itemsForm.push(a);
    this.itemsDataSource._updateChangeSubscription(); //neccessary to render the mat-table with the new row
  }
  ngOnInit() {
    this.itemForm = this.fb.group({
      items: this.fb.array([])
    });
    this.newItem();
    this.itemsDataSource.data = this.itemsForm.controls;
  }
}
like image 102
macosta Avatar answered Sep 20 '22 10:09

macosta


well let's assume u returning ur data from the server as Objects with a structure like IyourAwesomeData and for the purpose of this example, we will use field someName to filter the data

so ur ts component should look sth like this:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormControl } from '@angular/forms';
import { startWith, debounceTime, map, switchMap, distinctUntilChanged } from 'rxjs/operators';
import { Subscription } from 'rxjs';

interface IyourAwesomeData {
 someName: string; 
 someField: string;
 someOtherField: number;
}

export class YourAutcompleteComponent implements OnInit, OnDestroy {

  dataFiltered: IyourAwesomeData[]; // this data will be used inside HTML Template
  data: Observable<IyourAwesomeData[]>; 
  yourInputCtrl = new FormControl();
  private sub: Subscription;

  constructor() {}

  ngOnInit() {
    this.data = ??? // Pass your data as Observable<IyourAwesomeData[]>;
    this.sub = this.yourInputCtrl.valueChanges
      .pipe(
        debounceTime(500),
        distinctUntilChanged(), 
        startWith(''),
        switchMap((val) => {
          return this.filterData(val || '');
        })
      ).subscribe((filtered) => {
        this.dataFiltered = filtered;
      });
  }

  ngOnDestroy() {
     this.sub.unsubscribe();
  }

  filterData(value: string) {
    return this.data // like IyourAwesomeData[]
      .pipe(
        map((response) => response.filter((singleData: IyourAwesomeData) => {
          return singleData.someName.toLowerCase().includes(value.toLowerCase())
        })),
    );
  }
}

and ur HTML template should look sth like this:

<mat-form-field>
  <input matInput placeholder="some placeholder" [matAutocomplete]="auto" [formControl]="yourInputCtrl">
  <mat-autocomplete #auto="matAutocomplete">
    <mat-option *ngFor="let single of dataFiltered" [value]="single.someName">
      {{ single.someName }}
    </mat-option>
  </mat-autocomplete>
</mat-form-field>
like image 43
Annon_MS Avatar answered Sep 19 '22 10:09

Annon_MS