This is just madness , looks like there is no way to have a form which one of it's inputs is in a child component .
I have read all the blogs and tutorials and everything , no way to work this out .
The problem is when a child component is going to have any kind of form directives ( ngModel , ngModelGroup or whatever ..) , it wont work.
This is only a problem in template driven forms
This is the plunker :
import { Component } from '@angular/core';
@Component({
selector: 'child-form-component',
template: `
<fieldset ngModelGroup="address">
<div>
<label>Street:</label>
<input type="text" name="street" ngModel>
</div>
<div>
<label>Zip:</label>
<input type="text" name="zip" ngModel>
</div>
<div>
<label>City:</label>
<input type="text" name="city" ngModel>
</div>
</fieldset>`
})
export class childFormComponent{
}
@Component({
selector: 'form-component',
directives:[childFormComponent],
template: `
<form #form="ngForm" (ngSubmit)="submit(form.value)">
<fieldset ngModelGroup="name">
<div>
<label>Firstname:</label>
<input type="text" name="firstname" ngModel>
</div>
<div>
<label>Lastname:</label>
<input type="text" name="lastname" ngModel>
</div>
</fieldset>
<child-form-component></child-form-component>
<button type="submit">Submit</button>
</form>
<pre>
{{form.value | json}}
</pre>
<h4>Submitted</h4>
<pre>
{{value | json }}
</pre>
`
})
export class FormComponent {
value: any;
submit(form) {
this.value = form;
}
}
One simple solution is providing
ControlContainer
inviewProviders
array of your child component like:Stackblitz Example
Read also this article that explains why it's working.
Update
If you're looking for nested model driven form then here is the similar approach:
Ng-run Example
Update 2
If you don't know exactly which type of
ControlContainer
wraps your custom component(for example your controls is inside FormArray directive) then just use common version:Ng-run Example
Another possible workaround:
Just place this directive in a child component somewhere at the top of nodes hierarchy (before any ngModel).
How it works: NgModel qualifies parent form's dependency lookup with @Host(). So a form from a parent component is not visible to NgModel in a child component. But we can inject and provide it inside a child component using the code demonstrated above.
I've created a solution using a directive and service. Once you add those to your module, the only other code change you need to make are at the form level in the templates. This works with dynamically added form fields and AOT. It also supports multiple unrelated forms on a page. Here's the plunker: plunker.
It uses this directive:
And this service:
To use the directive in a parent component with a form:
Then in a child component:
From official docs:
This directive can only be used as a child of NgForm.
So I think you can try to wrap your child component in different
ngForm
, and expect in parent component result@Output
of child component. Let me know if you need more clarification.UPDATE: Here is Plunker with some changes, I converted child form to model driven, because there is no way to listen on form driven form for updated before it will be submited.
Reading through a bunch of related github issues [1] [2], I haven't found a straightforward way to make angular add a child
Component
's controls to a parentngForm
(some people also call them nested forms, nested inputs or complex controls).So what I'm going to show here is a workaround that works for me, using separate
ngForm
directives for parents and childs. It's not perfect, but it gets me close enough that I stopped there.I declare my
childFormComponent
with anngForm
directive (i.e. it's not a html form tag, only the directive):The Component then exposes the
addressFieldsForm
as a property, and also exports itself as a template reference variable:The parent form can then use the child form component like this:
Note that the submit button explicitly checks valid state on both the
ngFormAddress
and theaddressFields
form. That way I can at least sensibly compose complex forms, even though it has some boilerplate.