35

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 ?

1

6 Answers 6

34

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Just to add that as of now updateValue (from one of first answers) is being deprecated in favour of setValue
@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.
yep, it was (is?) totally not highlighted
29

Update

as of latest Update of angular2 syntax will be like this

this.form.controls['power'].setValue('anthing here');

2 Comments

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?
Is is possible to update a value in a nested form and update the parent component?
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

5 Comments

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 :)
That's what we currently have. You could try to fire a change event from each control to get the form model updated.
Add please your previous comment to the answer, this was the thing I was asking. Damn, this is bad news...
Should I post this on angular2 Issues page ?
Yes, I think it makes sense to create an issue for this. I tried the event but didn't make a difference.
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');
        });
    }
}

Comments

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...

1 Comment

What if the updated selectbox values doesn't contain the controller value?
0

The code is:

(<FormControl>this.form.controls['power']).updateValue(data);

1 Comment

FYI This no longer works in Angular 4 (possibly earlier).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.