219
votes

This is driving me nuts, I'm under the gun and can't afford to spend another whole day on this.

I am trying to manually set a control value ('dept') within the component, and it's just not working - even the new value logs to console properly.

Here is the FormBuilder Instance:

initForm() {
  this.form = this.fb.group({
    'name': ['', Validators.required],
    'dept': ['', Validators.required],
    'description': ['', Validators.required],
  });
}

This is the event handler that receives the selected dept:

deptSelected(selected: { id: string; text: string }) {
  console.log(selected) // Shows proper selection!

  // This is how I am trying to set the value
  this.form.controls['dept'].value = selected.id;
}

Now when the form is submitted and I log out this.form the field is still blank! I've seen other ppl use updateValue() but this is beta.1 and I don't see that as a valid method to call on the control.

I have also tried to call updateValueAndValidity() with no success :(.

I would just use ngControl="dept" on the form element, like I'm doing with the rest of the form but its a custom directive/component.

<ng-select
  [data]="dept"
  [multiple]="false"
  [items]="depts"
  (selected)="deptSelected($event)" <!-- This is how the value gets to me -->
  [placeholder]="'No Dept Selected'"></ng-select>
11
I had run into similar situation, the scenario was the value was set in http.get-subscribe and load the form value, but setting the value line getting executed first, the subscribe really get executed later as its asynchronous. so setting the value in the subscribe make sure its set. my2cents!HydTechie

11 Answers

415
votes

Updated: 19/03/2017

this.form.controls['dept'].setValue(selected.id);

OLD:

For now we are forced to do a type cast:

(<Control>this.form.controls['dept']).updateValue(selected.id)

Not very elegant I agree. Hope this gets improved in future versions.

106
votes

In Angular 2 Final (RC5+) there are new APIs for updating form values. The patchValue() API method supports partial form updates, where we only need to specify some of the fields:

this.form.patchValue({id: selected.id})

There is also the setValue() API method that needs an object with all the form fields. If there is a field missing, we will get an error.

19
votes

Aangular 2 final has updated APIs. They have added many methods for this.

To update the form control from controller do this:

this.form.controls['dept'].setValue(selected.id);

this.form.controls['dept'].patchValue(selected.id);

No need to reset the errors

References

https://angular.io/docs/ts/latest/api/forms/index/FormControl-class.html

https://toddmotto.com/angular-2-form-controls-patch-value-set-value

12
votes

You can use the following methods to update the value of a reactive form control. Any of the following method will suit for your need.

Methods using setValue()

this.form.get("dept").setValue(selected.id);
this.form.controls["dept"].setValue(selected.id);

Methods using patchValue()

this.form.get("dept").patchValue(selected.id);
this.form.controls['dept'].patchValue(selected.id);
this.form.patchValue({"dept": selected.id});

Last method will loop thorough all the controls in the form so it is not preferred when updating single control

You can use any of the method inside the event handler

deptSelected(selected: { id: string; text: string }) {
     // any of the above method can be added here
}

You can update multiple controls in the form group if required using the

this.form.patchValue({"dept": selected.id, "description":"description value"});
10
votes

You could try this:

deptSelected(selected: { id: string; text: string }) {
  console.log(selected) // Shows proper selection!

  // This is how I am trying to set the value
  this.form.controls['dept'].updateValue(selected.id);
}

For more details, you could have a look at the corresponding JS Doc regarding the second parameter of the updateValue method: https://github.com/angular/angular/blob/master/modules/angular2/src/common/forms/model.ts#L269.

9
votes

If you are using form control then the simplest way to do this:

this.FormName.get('ControlName').setValue(value);
6
votes

None of these worked for me. I had to do:

  this.myForm.get('myVal').setValue(val);
5
votes
  let cloneObj = Object.assign({}, this.form.getRawValue(), someClass);
  this.form.complexForm.patchValue(cloneObj);

If you don't want manually set each field.

5
votes

I know the answer is already given but I want give a bit brief answer how to update value of a form so that other new comers can get a clear idea.

your form structure is so perfect to use it as an example. so, throughout my answer I will denote it as the form.

this.form = this.fb.group({
    'name': ['', Validators.required],
    'dept': ['', Validators.required],
    'description': ['', Validators.required]
  });

so our form is a FormGroup type of object that has three FormControl.

There are two ways to update the model value:

  • Use the setValue() method to set a new value for an individual control. The setValue() method strictly adheres to the structure of the form group and replaces the entire value for the control.

  • Use the patchValue() method to replace any properties defined in the object that have changed in the form model.

The strict checks of the setValue() method help catch nesting errors in complex forms, while patchValue() fails silently on those errors.

From Angular official documentation here

so, When updating the value for a form group instance that contains multiple controls, but you may only want to update parts of the model. patchValue() is the one you are looking for.

lets see example. When you use patchValue()

this.form.patchValue({
    dept: 1 
});
//here we are just updating only dept field and it will work.

but when you use setValue() you need to update the full model as it strictly adheres the structure of the form group. so, if we write

this.form.setValue({
    dept: 1 
});
// it will throw error.

We must pass all the properties of the form group model. like this

this.form.setValue({
      name: 'Mr. Bean'
      dept: 1,
      description: 'spome description'
  });

but I don't use this style frequently. I prefer using the following approach that helps to keep my code cleaner and more understandable.

What I do is, I declare all the controls as a seperate variable and use setValue() to update that specific control.

for the above form, I will do something like this.

get companyIdentifier(): FormControl {
    return this.form.get('name') as FormControl;
}

get dept(): FormControl {
    return this.form.get('dept') as FormControl;
}

get description(): FormControl {
    return this.form.get('description') as FormControl;
}

when you need to update the form control just use that property to update it. In the example the questioner tried to update the dept form control when user select an item from the drop down list.

deptSelected(selected: { id: string; text: string }) {
  console.log(selected) // Shows proper selection!

  // instead of using this.form.controls['dept'].setValue(selected.id), I prefer the following.

  this.dept.setValue(selected.id); // this.dept is the property that returns the 'dept' FormControl of the form.
}

I suggest to have a look FormGroup API to get know how of all the properties and methods of FormGroup.

Additional: to know about getter see here

3
votes

@Filoche's Angular 2 updated solution. Using FormControl

(<Control>this.form.controls['dept']).updateValue(selected.id)

import { FormControl } from '@angular/forms';

(<FormControl>this.form.controls['dept']).setValue(selected.id));

Alternatively you can use @AngularUniversity's solution which uses patchValue

-1
votes

Tip: If you're using setValue but not providing every property on the form you'll get an error:

Must supply a value for form control with name: 'stateOrProvince'.

So you may be tempted to use patchValue, but this can be dangerous if you're trying to update a whole form. I have an address that may not have stateOrProvince or stateCd depending upon whether it is US or worldwide.

Instead you can update like this - which will use the nulls as defaults:

this.form.setValue( { stateOrProvince: null, stateCd: null, ...address } );