Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 form spread across components

I am trying to create a forms component where the component provides the <form> and its descendants the form content, i.e. control. I am using RC4 with reactive forms. The component should be used like this:

<my-formwizard [form]="form">
  <input formControlName="name" type="text" />
</my-formwizard>

Here's a plunk showing the implementation: http://plnkr.co/edit/OSzjDQD63lwoEsyqdLvw?p=preview

I run into an exception: TypeError: Cannot read property 'setParent' of null

Is there a way to accomplish a reactive form spread across multiple components?


UPDATE: RC5 has a clearer error message and thanks to peeskillet's input, formControlName can be used if the custom directive gets the FormGroup attached through the formGroup property. The updated plunk shows the form spread across two components working:

http://plnkr.co/edit/1VfIH5AYjoe7dmizw6ss?p=preview

like image 335
achimha Avatar asked Jul 29 '16 13:07

achimha


1 Answers

In you Plunker, I'm not sure why you have the ngForm

<my-formwizard [form]="form" ngForm="form">

but that shouldn't be there. I think it may even be creating a whole new form. That should be removed. Once you remove that, then you will run into another problem, saying that there is no ControlContainer. The ControlContainer is the FormGroupDirective ([formGroup]).

The problem is caused by the formControlName. If you look at the source for the FormControlName directive, and you look at the constructor, you will see that it requires a ControlContainer dependency. But not just that, it also has a @Host1 decorator, which means it will only look for the ControlContainer in the host injector.

Honestly I'm not quite sure in this case which injector is used as the host injector in this case, but it appears it is not the one with the form group directive. Maybe because how you have the components set up.

A solution I found it to instead of using formControlName, use [formControl] instead, and just pass a FormControl instance. The FormControlDirective does not have this problem (where it needs a ControlContainer), as it is possible to be used in standalone.

So you could do this instead

<input [formControl]="nameCtrl" type="text" />

export class App {

  form: FormGroup;
  nameCtrl: FormControl;

  constructor(fb: FormBuilder) {
    this.nameCtrl = new FormControl('');
    this.form = fb.group({
      name: this.nameCtrl
    });
  }
}

This solves your problem. Here's the updated Plunker,

See Also:

  • How to tackle creating complex form with lots of custom components? for some design ideas.

1 - See Host and Visibility... for a good read on this topic

like image 81
Paul Samsotha Avatar answered Oct 20 '22 17:10

Paul Samsotha