Lint
Lint

Reputation: 935

Autocomplete not detecting the correct value from object properties Angular

I've a huge list of counties and want to implement an auto complete feature. I'm using the same form to add a new customer or update an existing customer.

Now, the problem is that for adding a new customer, my program works perfectly, but when I updates it, in county dropdown list it show the countyId instead of name. How do achieve that ? see the images in order

county schema is as

{
  countyId: number;
  name:string
}

I'm trying with the following code in html

<mat-form-field appearance="outline" fxFlex="50" class="pr-4">
    <mat-label>County</mat-label>
    <input type="text" placeholder="County" name="" matInput formControlName="countyId" [matAutocomplete]="auto">

    <mat-autocomplete autoActiveFirstOption #auto="matAutocomplete">
        <mat-option *ngFor="let county of filteredCounties | async" [value]="county.name">
            {{county.name}}
        </mat-option>
    </mat-autocomplete>
</mat-form-field>

and in my component file

import { Component, OnInit, Inject, ViewChild, AfterViewInit, ElementRef, ComponentRef } from '@angular/core';
import { FormGroup, FormControl, FormBuilder, Validators } from '@angular/forms';
import { Router, ActivatedRoute } from '@angular/router';
import { CustomerService } from '../../../../services/customer/customer.service';
import { CountyService } from '../../../../services/county/county.service';
import { SubCountyService } from '../../../../services/subCounty/sub-county.service';
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import PNotify from 'pnotify/dist/es/PNotify';
import { Observable } from 'rxjs';
import { map, startWith } from 'rxjs/operators';

@Component({
  selector: 'app-new-customer',
  templateUrl: './new-customer.component.html',
  styleUrls: ['./new-customer.component.scss']
})

export class NewCustomerComponent implements OnInit {
  dataSending = false;
  customerId;
  updatePerson;
  updatedCustomer;
  ready = false;
  dialogView;
  ref: ComponentRef<any>;
  newCustomerForm: FormGroup;
  counties; // list of counties
  subCounties;
  filteredCounties: Observable<string[]>;

  constructor(
    private _formBuilder: FormBuilder,
    private router: Router,
    private route: ActivatedRoute,
    private customerService: CustomerService,
    private countyService: CountyService,
    private subCountyService: SubCountyService,
    public dialogRef: MatDialogRef<NewCustomerComponent>,
    @Inject(MAT_DIALOG_DATA) public display: any
  ) {
    this.dialogView = display.view;
    this.route.paramMap.subscribe((params) => {
      this.customerId = params.get('customerId');
      if (this.customerId) {
        this.customerService.getCustomer(this.customerId).subscribe((response) => {
          this.updatePerson = response;
          this.newCustomerForm = this._formBuilder.group({
            name: [this.updatePerson.name, Validators.required],
            nationalId: [this.updatePerson.nationalId, Validators.required],
            gender: [this.updatePerson.gender, Validators.required],
            phone1: [this.updatePerson.phone1],
            phone2: [this.updatePerson.phone2],
            bishopName: [this.updatePerson.bishopName, Validators.required],
            bishopPhone: [this.updatePerson.bishopPhone, Validators.required],
            countyId: [this.updatePerson.countyId, Validators.required],
            county: [this.updatePerson.county, Validators.required],
            subCountyId: [this.updatePerson.subCountyId, Validators.required],
            address: [this.updatePerson.address, Validators.required],
            additionalInfo: [this.updatePerson.additionalInfo],
            input1: [this.updatePerson.input1],
            input2: [this.updatePerson.input2],
            defaultingRecord: [''],
          });
          this.ready = true;
        });
      }
      else {
        this.ready = true;
        this.newCustomerForm = this._formBuilder.group({
          nationalId: ['', Validators.required],
          name: ['', Validators.required],
          gender: ['', Validators.required],
          phone1: [''],
          phone2: [''],
          county: [''],
          countyId: ['', Validators.required],
          subCountyId: ['', Validators.required],
          bishopName: ['', Validators.required],
          bishopPhone: ['', Validators.required],
          address: ['', Validators.required],
          additionalInfo: [''],
          input1: [''],
          input2: [''],
          defaultingRecord: [''],
        });
      }
    });
  }

  // tslint:disable:typedef
  ngOnInit() {
    // Getting the list of counties
    this.countyService.getCounties().subscribe((response) => {
      this.counties = response;
      this.newCustomerForm.patchValue({
        county: response
      });
      if (!this.customerId) {

        this.filteredCounties = this.newCustomerForm.get('county').valueChanges.pipe(
          startWith(''),
          map(value => typeof value === 'string' ? value : value.name),
          map(value => this._filter(value))
        );
      }
    }, error => {
      this.counties = [
        {
          "countyId": 63,
          "name": "Mombasa"
        },
        {
          "countyId": 64,
          "name": "Isiolo"
        },
        {
          "countyId": 65,
          "name": "Murang'a"
        },
        {
          "countyId": 66,
          "name": "Laikipia"
        },
        {
          "countyId": 67,
          "name": "Siaya"
        },
        {
          "countyId": 68,
          "name": "Kwale"
        },
        {
          "countyId": 69,
          "name": "Meru"
        },
        {
          "countyId": 70,
          "name": "Kiambu"
        },
        {
          "countyId": 71,
          "name": "Nakuru"
        },
        {
          "countyId": 72,
          "name": "Kisumu"
        },
        {
          "countyId": 73,
          "name": "Kilifi"
        },
        {
          "countyId": 74,
          "name": "Tharaka-Nithi"
        },
        {
          "countyId": 75,
          "name": "Turkana"
        },
        {
          "countyId": 76,
          "name": "Narok"
        },
        {
          "countyId": 77,
          "name": "Homa Bay"
        },
        {
          "countyId": 78,
          "name": "Tana River"
        },
        {
          "countyId": 79,
          "name": "Embu"
        },
        {
          "countyId": 80,
          "name": "West Pokot"
        },
        {
          "countyId": 81,
          "name": "Kajiado"
        },
        {
          "countyId": 82,
          "name": "Migori"
        },
        {
          "countyId": 83,
          "name": "Lamu"
        },
        {
          "countyId": 84,
          "name": "Kitui"
        },
        {
          "countyId": 85,
          "name": "Samburu"
        },
        {
          "countyId": 86,
          "name": "Kericho"
        },
        {
          "countyId": 87,
          "name": "Kisii"
        },
        {
          "countyId": 88,
          "name": "Taita-Taveta"
        },
        {
          "countyId": 89,
          "name": "Machakos"
        },
        {
          "countyId": 90,
          "name": "Trans Nzoia"
        },
        {
          "countyId": 91,
          "name": "Bomet"
        },
        {
          "countyId": 92,
          "name": "Nyamira"
        },
        {
          "countyId": 93,
          "name": "Garissa"
        },
        {
          "countyId": 94,
          "name": "Makueni"
        },
        {
          "countyId": 95,
          "name": "Uasin Gishu"
        },
        {
          "countyId": 96,
          "name": "Kakamega"
        },
        {
          "countyId": 97,
          "name": "Nairobi"
        },
        {
          "countyId": 98,
          "name": "Wajir"
        },
        {
          "countyId": 99,
          "name": "Nyandarua"
        },
        {
          "countyId": 100,
          "name": "Elgeyo-Marakwet"
        },
        {
          "countyId": 101,
          "name": "Vihiga"
        },
        {
          "countyId": 102,
          "name": "Mandera"
        },
        {
          "countyId": 103,
          "name": "Nyeri"
        },
        {
          "countyId": 104,
          "name": "Nandi"
        },
        {
          "countyId": 105,
          "name": "Bungoma"
        },
        {
          "countyId": 106,
          "name": "Marsabit"
        },
        {
          "countyId": 107,
          "name": "Kirinyaga"
        },
        {
          "countyId": 108,
          "name": "Baringo"
        },
        {
          "countyId": 109,
          "name": "Busia"
        }
      ];
    });
    // Getting a list of sub-counties
    this.subCountyService.getSubCounties().subscribe((response) => {
      this.subCounties = response;
    });
  }
  displayFn(county?: any): string | undefined {
    return county ? county.name : undefined
  }
  private _filter(value) {
    console.log('value: ', value);
    const filterValue = value.toLowerCase();
    return this.counties.filter(county => county.name.toLowerCase().indexOf(filterValue) === 0);
  }
  addCustomer(customer) {
    console.log('Value of customer form before setting is: ', this.newCustomerForm.value);
    const selectedCountyId = this.counties.filter(county => county.name === this.newCustomerForm.value.countyId)[0];
    console.log('CountyId: ', selectedCountyId);
    if (!selectedCountyId) {
      PNotify.error({
        title: 'Please selecte a valid county',
        minHeight: '75px'
      });
      return;
    }
    this.newCustomerForm.patchValue({
      countyId: selectedCountyId.countyId
    });
    customer.countyId = selectedCountyId.countyId;
    console.log('Value of customer form after setting is: ', this.newCustomerForm.value);
    this.dataSending = true;
    this.customerService.addCustomer(customer).subscribe((response) => {
      if (this.dialogView) {
        PNotify.success({
          title: 'Customer added Successfully',
          minHeight: '75px'
        });
        this.dialogRef.close();
      }
      else {
        PNotify.success({
          title: 'Customer added Successfully',
          text: 'Redirecting to list page',
          minHeight: '75px'
        });
        this.dataSending = false;
        document.getElementById('submitButton').style.display = 'initial';
        this.router.navigate(['searchcustomer']);
      }

    }, (error) => {
      console.log('Following error occured: ', error);
      PNotify.error({
        title: 'Error occured while adding customer',
        text: 'Failed to add new customer',
        minHeight: '75px'
      });
      this.dataSending = false;
    });
  }

  updateCustomer(customer) {
    this.dataSending = true;
    this.updatedCustomer = this._formBuilder.group({
      customerId: [this.customerId],
      nationalId: [customer.nationalId],
      name: [customer.name],
      gender: [customer.gender],
      phone1: [customer.phone1],
      phone2: [customer.phone2],
      countyId: [customer.countyId],
      subCountyId: [customer.subCountyId],
      address: [customer.address],
      additionalInfo: [customer.additionalInfo],
      bishopName: [customer.bishopName],
      bishopPhone: [customer.bishopPhone],
      input1: [customer.input1],
      input2: [customer.input2],
    });

    this.customerService.updateCustomer(this.updatedCustomer.value, this.customerId).subscribe((response) => {
      PNotify.success({
        title: 'Customer updated Successfully',
        text: 'Redirecting to list page',
        minHeight: '75px'
      });
      this.dataSending = false;
      this.router.navigate(['searchcustomer']);
    }, (error) => {
      console.log('An error occured while updating customer: ', error);
      PNotify.error({
        title: 'Error occured while updating customer',
        text: 'Failed to update customer',
        minHeight: '75px'
      });
      this.dataSending = false;
    });
  }
}



Pictures for better understanding Image 1 Image 2 Image 3

Upvotes: 0

Views: 1853

Answers (1)

AVJT82
AVJT82

Reputation: 73377

If you feed the autocomplete an id, that is what it will show. In your first image where you say it works, it looks like it works, but in fact it is not storing the countyId when a choice is made, but the name property which you have set as value. I would assume that it is actually the id you want stored there too.

The cleanest solution in my opinion, is to actually store the whole county object. So I would suggest the following:

<input type="text" matInput formControlName="county" [matAutocomplete]="auto">

<mat-autocomplete autoActiveFirstOption #auto="matAutocomplete" [displayWith]="displayFn">
  <mat-option *ngFor="let county of filteredCounties | async" [value]="county">
    {{county.name}}
  </mat-option>
</mat-autocomplete>

with that I removed the countyId formcontrol and instead added county, which stores the whole object and added displayWith to show the name property of the county.

Then modify the valueChanges to check if user has typed or it has been fed an object:

// add the correct name of your form
this.filteredCounties = this.myForm
  .get("county")
  .valueChanges.pipe(
    startWith(""),
    map(value => typeof value === 'string' ? value : value.name),
    map(value => this._filter(value))
  );

and the displayFn which is shown in template:

// don't use 'any' !!
displayFn(county?: any): string | undefined {
  return county ? county.name : undefined
}

So now is only left the option where you want to create the edit form. If you only have the countyId property, you can use find to add the correct object. Here in this sample I set it on creation, but you will maybe use setValue(), but the idea is the same!

// replace 2 with the variable/prop you have the desired id
county: [this.counties.find(x => x.countyId === 2)],

So now you have the whole object. When submitting form and if you only want the countyId from the form control, you can access it by: this.myForm.get('county').value.countyId.

STACKBLITZ with the above code.

Upvotes: 1

Related Questions