Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting selected option of select control in an Angular 2 model-driven form

Tags:

html

angular

I have researched many similar existing answers on SO and elsewhere, but just can't find the solution to this.

I'm using the model-driven approach in Angular 2 to build my form, which is both an add and edit form. When in edit mode, the values are populated with data retrieved from a service: this aspect is all fine because the simple text inputs all bind correctly.

One of the properties is 'Country' and this is an object as follows:

    export class Country {id: number; name: string;}

I want to bind this to a select control which will have the list of countries available, and the one from the model populated when the form loads. I want the value of the binding to be the country object, not just the id.

Here's the html of the select control:

    <select class="form-control" id="country" formControlName="country">
          <option value="default">--Select a country--</option>
          <option *ngFor="let c of countries" [value]="c">{{c.name}}      </option>
</select> 

And here is where i try to to populate the value from the component class:

    (<FormControl>this.personForm.controls['country'])
 .setValue(this.person.country, { onlySelf: true });

But there is no selected option when the page loads, even though the console confirms that this.person.country exists and is populated with the correct object.

I can get it working with ids: changing to [value]="c.id" in the view and appending .id in the class, and then it works in that the right option is selected. The problem is that the select no longer emits an object for the country property, just the id. I tried changing [value] to [ngValue] and get the same result. I even added [ngModel]="country" to the select element and that didn't help either.

I'd be grateful for any help.

like image 880
Matt Avatar asked Dec 05 '16 17:12

Matt


People also ask

How do you use Selectcontrolvalueaccessor?

How to use select controls with form directives. To use a select in a template-driven form, simply add an ngModel and a name attribute to the main <select> tag. In reactive forms, you'll also want to add your form directive ( formControlName or formControl ) on the main <select> tag.

How can I bind a form to a model in Angular 6 using reactive forms?

It's done thru the [formGroup]="this. myFormGroup" directive. This binds it to the model stored in the FormGroup object, which you can later get at by calling this.

How does Angular determine change in form control?

In Angular we have observables which subscribe to form value changes. what you have to do is, subscribe to the form instance and detect any changes to the form. Suppose you don't want to include save button on your form. whenever user change any thing in the form save data to the server.


1 Answers

The issue is most likely that this.person.country is not the same country as in your countries array.

If we want to make them the same we can either explicitly subscribe to the valueChanges of the select control or bind [(ngModel)] to person.country:

subscribe to changes

code

this.countryForm.controls['country'].valueChanges.subscribe(country => 
  this.person.country = country;
);

// initialize by finding the correct country object (this will overwrite the person's country object)
this.countryForm.controls['country'].setValue(countries.filter(c => c.id === person.country.id));

template

ngModel bind

We still have to make the objects match (compare strategy that Angular 2 uses which is really what JS uses)

code

this.person.country = this.countries.filter(c => c.id === this.person.country.id)[0];

template

<select class="form-control" id="country" formControlName="country" [(ngModel)]="person.country">
    <option value="default">--Select a country--</option>
    <option *ngFor="let c of countries" [ngValue]="c">{{c.name}}</option>
</select>

ngModel Plunker: http://plnkr.co/edit/UIS2V5rKh77n4JsjZtii?p=preview

subscription Plunker: http://plnkr.co/edit/yyZ6ol1NPD77nyuzwS2t?p=info

like image 131
silentsod Avatar answered Oct 27 '22 02:10

silentsod