Skip to content
Advertisement

Angular: Material Autocomplete populated with api data returns JSON value

I am new to angular and am working on a small ledger application. In it, the user has to select customer from a material autocomplete field which is populated with data from an API. Like so:

PHP Back-end

    <?php

require 'database.php';

$nhiu_customers = [];
$sql = "SELECT cust_name FROM customer_table";

if($result = mysqli_query($con,$sql))
{
  $i = 0;
  while($row = mysqli_fetch_assoc($result))
  {
    $customers[$i]['cust_name'] = $row['cust_name'];
    $i++;
  }

  echo json_encode($customers);
}
else
{
  http_response_code(404);
}

Angular Component.html

{{incomeForm.value | json}}
<form [formGroup]="Form">

<p> <mat-form-field class="customer">
    <input type="text" matInput placeholder="Select Customer" 
    [matAutocomplete]="auto" formControlName="customerName">
    <mat-autocomplete #auto="matAutocomplete" [displayWith]="getOptionText">
    <mat-option *ngFor="let option of filteredOptions | async" [value]="option">
        {{option.cust_name}}
    </mat-option>
    </mat-autocomplete>
</mat-form-field> 

</p>

Angular Component.TS

import { Component, OnInit, Injectable } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
import {Observable, of, Subscription} from 'rxjs';
import {map, startWith, switchMap, tap, debounceTime} from 'rxjs/operators';
import { ApiService } from '../api.service';

export class Component implements OnInit{

Form = new FormGroup({
  customerName: new FormControl('')
});

filteredOptions: Observable<string>;

ngOnInit() {
  this.filteredOptions = this.Form.controls['customerName'].valueChanges.pipe(
    startWith(""),
    debounceTime(300),
    switchMap(value => this.doFilter(value))
  );

  doFilter(value){
    return this.service.getData().pipe(
      map(response =>
        response.filter(option => {
          return option.cust_name.indexOf(value) === 0;
        })
      )
    );

  }

  getOptionText(option) {
    return  option.cust_name;
  }

}

Angular API Service

export class ApiService {

  constructor(private httpClient: HttpClient) { }

opts = [];

getData() {
  return this.opts.length
    ? of(this.opts)
    : this.httpClient
    .get<any>("http://localhost/api/read.php")
    .pipe(tap(data => (this.opts = data)));

}
}

Material autocomplete is working fine, it populates data from the api. But the problem is that when I select a customer’s name from the list, the JSON package of the form that I have to post takes the JSON encoded value of the customer name instead of regular text input (see image below). Ideally the form should produce JSON value “customerName”: “Customer Name” for formControl customerName.

[https://i.stack.imgur.com/pcDg4.jpg

What am I doing wrong?

Advertisement

Answer

That’s happening due to [value] attribute for option.

If you set value as option.name, then the form control will have just the name and not object and you won’t need displayWith function.

  <mat-option *ngFor="let option of filteredOptions | async" [value]="option.name">
    {{option.name}}
  </mat-option>

There is a reason why you should set the option as it is to the form control. Generally you would want to send option id (in your case, customer id) to server so as to identify the selected record.

Example Showing Autocomplete

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement