34

I have a problem building dynamic angular2 forms with controls and select boxes, for example this plunker:

    <select class="form-control" ngControl="power">
      <option *ngFor="#p of powers" [value]="p">{{p}}</option>
    </select>

You can select a hero power, and the control will have the same value. But if you press Change Powers, the selected value would be null but the control value is still the old value. This is a serious problem I think as this is a source of a lot of bugs when the form shows one thing but in reality it will submit something different, is there some way to update the content of the control ? There is updateValue() but you have to manually set the value in all those cases.

There is also a similar case when you update the selectbox options after the form building, it will show a selected value in the selectedbox, while the control value would be null, any ideas on how to deal with this ?

Silencer
  • 1,602
  • 4
  • 17
  • 27
  • 1
    Possible duplicate of [Angular2 - Manually Set Value for FormBuilder Control](http://stackoverflow.com/questions/35039610/angular2-manually-set-value-for-formbuilder-control) – Angular University Aug 18 '16 at 17:36

7 Answers7

33

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.

Angular University
  • 42,341
  • 15
  • 74
  • 81
  • 6
    Just to add that as of now `updateValue` (from one of first answers) is being deprecated in favour of `setValue` – superjos Aug 30 '16 at 00:18
  • 1
    @superjos You have no idea how long I searched for this information and here it was buried in a comment on an answer. Nothing in the changelog. – chap Nov 16 '16 at 01:50
  • 1
    yep, it was (is?) totally not highlighted – superjos Nov 16 '16 at 09:59
28

Update

as of latest Update of angular2 syntax will be like this

this.form.controls['power'].setValue('anthing here');
Community
  • 1
  • 1
Pardeep Jain
  • 84,110
  • 37
  • 165
  • 215
  • lets say I have a directive that is replacing an input with a widget... how can my directive get access to the `form` or formControl object? – Brad Kent Dec 09 '16 at 18:36
  • Is is possible to update a value in a nested form and update the parent component? – Adam Mendoza Feb 11 '17 at 05:25
6

Currently this is the only thing you can do (as mentioned in the question)

this.form.controls['power'].updateValue(null);

There is an open issue to allow to reset a form https://github.com/angular/angular/issues/4933

There is also a pull request but that also allows you to to it "manually" for each control but also allows to reset states like pristine, touched, ... https://github.com/angular/angular/pull/6679

Silencer
  • 1,602
  • 4
  • 17
  • 27
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • As I said the problem with `updateValue()` is that each time in a form I have dynamic elements I should update each value with it? Form reset is another thing, I need all values in a complex form to be up to date, not to reset it :) – Silencer Feb 23 '16 at 14:01
  • That's what we currently have. You could try to fire a `change` event from each control to get the form model updated. – Günter Zöchbauer Feb 23 '16 at 14:02
  • Add please your previous comment to the answer, this was the thing I was asking. Damn, this is bad news... – Silencer Feb 23 '16 at 14:04
  • Should I post this on angular2 Issues page ? – Silencer Feb 23 '16 at 14:10
  • Yes, I think it makes sense to create an issue for this. I tried the event but didn't make a difference. – Günter Zöchbauer Feb 23 '16 at 14:21
5

[Angular 2 Stable]

Here's a dirty way just using NgModel (and without importing other form-builder or form-group modules)

//
// set form field, "foo" value to "bar"
//

//
// view
//
<form #formRef="ngForm">
    <input name="foo" [(ngModel)]="foo"></input>
</form>

//
// controller
//
class {
    @ViewChild('formRef') form: NgModel;

    ngAfterViewInit() {
        setTimeout(() => {
          this.form['controls']['foo'].setValue('bar');
        });
    }
}
James Salamon
  • 1,412
  • 1
  • 22
  • 18
1

You can try to keep form sort of immutable. When you need to reset it you just rebuild it. This way can be sure it's up to date. You can also keep values stored somewhere and reset form to those values. Say you're editing an item, when you reset you can revert to the original values, not just an empty form...

export class TheForm {
  public form: ControlGroup;
  public controls = (value: any = {}) => ({
    'id': [value.id],
    'name': [value.name, Validators.required]
  });

  constructor() {
    let values = some_values_from_database || {};
    this.build(values);
  }

  build(value) {
    this.form = this._builder.group(this.controls(value));
  }

  submit() {
    console.log(this.form.value);
  }
}

I've created the base form that handles this kind of functionality with @ngrx/store, here's the Gist. When I need a form for different model, I'll extend BaseForm and just define controls and submit() method, the rest is inherited...

Sasxa
  • 40,334
  • 16
  • 88
  • 102
0

The code is:

(<FormControl>this.form.controls['power']).updateValue(data);
Nicolas Molina
  • 339
  • 2
  • 3
0

Angular 16:

this.YOUR_FORM.controls.YOUR_FORM_CONTROL_NAME.setValue(NEW_VALUE)

Example:

this.testForm.controls.username.setValue("bla bla");
hakki
  • 6,181
  • 6
  • 62
  • 106