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.
[
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.