n_denny
n_denny

Reputation: 405

Autocomplete input for filter more options within FormGroup

I need to implement a simple autocomplete textbox that allow to choose from list of objects filtered and displayed by name.

For example i have a array of Country objects that have some property (countryName, countryCode, countryId.. so on), i want to display and filter in the textbox by countryName but once user select the country i want that whole object gets selected.

I could solve this problem with [(ngModel)] or FormControl but now i have to use FormGroup and i can't figure out how to use property formControlName="..."

here's snippet example:

.html

<form [formGroup]="formGroup">
 [...]
  <mat-form-field>
    <input type="text" placeholder="{{'BIRTH_COUNTRY'|translate}}" matInput formControlName="birthCountry"
      [matAutocomplete]="auto" required>
    <mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn">
      <mat-option *ngFor="let country of countries" [value]="country">
        {{country.CountryName}}
      </mat-option>
    </mat-autocomplete>
  </mat-form-field>
</form>

.ts

export class PersonalDataComponent implements OnInit {
  public formGroup: FormGroup;

  countries?: Country[];

  constructor(public service: RegisterService) {
    this.formGroup = new FormGroup({
      name: new FormControl(null, Validators.required),
      lastName: new FormControl(null, Validators.required),
      gender: new FormControl(null, Validators.required),
      birthDate: new FormControl(null, Validators.compose([Validators.required, legalAgeValidator])),
      birthCountry: new FormControl(null, Validators.required),
    });

    displayFn(country ?: Country): string | undefined {
      return country ? country.CountryName : undefined;
    }

  }
}

is there any solution to use a autocomplete textbox/select to filter object list and bind the selected element to a FormGroup element?

Upvotes: 3

Views: 2965

Answers (1)

Giwrgos Lampadaridis
Giwrgos Lampadaridis

Reputation: 326

Edit:

Ok I got it to work with autoComplete. Here is my code:

HTML:

        <mat-form-field>
          <input type="text" placeholder="Country" aria-label="Country" matInput formControlName="country"
            [matAutocomplete]="auto">
          <mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn">
            <mat-option *ngFor="let country of filteredCountries | async" [value]="country">
              {{country.name}}
            </mat-option>
          </mat-autocomplete>
        </mat-form-field>

TS: Before @Component

import {Observable} from 'rxjs';
import {map, startWith} from 'rxjs/operators';
import { FormBuilder, Validators } from '@angular/forms';
export interface Country {
  name: string;
  id: string;
}

Before constructor:

 public formGroup;
 countries: Country[] = [{"name": 'Greece', "id": "1"}, {"name": 'Italy', "id": "2"}, {"name": 'Spain', "id": "3"}]
 filteredCountries: Observable<Country[]>;

Constructor:

constructor(public formBuilder: FormBuilder)

After constructor:

this.formGroup =  this.formBuilder.group({
country: ['', Validators.required]});

On ngOnInit:

 this.filteredCountries = this.formGroup.get('country').valueChanges
      .pipe(
        startWith<string | Country>(''),
        map(value => typeof value === 'string' ? value : (<any>value).name),
        map(name => name ? this._filter(name) : this.countries.slice())
      );

Additional functions:

 displayFn(country?: Country): string | undefined {
    return country ? country.name : undefined;
  }

  private _filter(name): Country[] {
    const filterValue = name.toLowerCase();

    return this.countries.filter(option => option.name.toLowerCase().indexOf(filterValue) === 0);
  }

I used the material documentation to get it to work, and added it to an existing project of mine. If you find any region reference instead of country its because that was the keyword in my project and I apologize in advance. This will make the value take the whole object. You can test and print console.log(this.formGroup.value); onSubmit.

Upvotes: 3

Related Questions