In an Angular 16 app I have a template driven form that will directly contain a text field and my submit button. It also contains a component that will contain some common reusable form fields, so I pass my form reference as an input to it.
I am having a problem where the fields inside of the component are not added to my form. How do I associate an input with a form from within the component? See my demo link below.
The problem is that the fields inside the component are not added to the form, and thus when they are invalid they do not affect the parent form.
Here's the code directly in my question, but the above link will be a better example
The host component with the form
<form #myForm="ngForm" (ngSubmit)="submit(myForm)">
<label for="fieldOne">One (directly in form)</label>
<input
type="text"
id="fieldOne"
name="fieldOne"
[ngClass]="{
'is-invalid': fieldOne.invalid && (fieldOne.touched || myForm.submitted)
}"
required
#fieldOne="ngModel"
[(ngModel)]="fieldOneVal"
/>
<br /><br />
<app-form-editor [form]="myForm"/>
<br />
<button type="submit">Submit</button>
<strong *ngIf="submitSuccess" class="text-success">Sucessfully submitted!</strong>
<br />
<pre>myForm.valid: {{myForm.valid}}</pre>
<pre>myForm.value: {{myForm.value | json}}</pre>
</form>
The <app-form-editor>
import { Component, Input, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms';
@Component({
selector: 'app-form-editor',
templateUrl: './form-editor.component.html',
})
export class FormEditorComponent implements OnInit {
@Input() form!: NgForm;
fieldTwoVal = '';
ngOnInit(): void {}
}
<label for="fieldTwo" class="control-label">Two (Inside Component)</label>
<input
name="fieldTwo"
id="fieldTwo"
[ngClass]="{
'is-invalid': fieldTwo.invalid && (fieldTwo.touched || form.submitted)
}"
required
[(ngModel)]="fieldTwoVal"
#fieldTwo="ngModel"
/>
<br />
<pre>component form.valid: {{ form.valid }}</pre>
<pre>component form.value: {{ form.value | json }}</pre>
Just add a viewProvider in your app-form-editor.
@Component({
selector: 'app-form-editor',
templateUrl: './form-editor.component.html',
viewProviders:[{ provide: ControlContainer, useExisting: NgForm }]
})
You can think like in your child component you need add a "form ngForm" but You choose not add else use the existing
NOTE: If we are working with reactiveForms the viewProvider to add is the viewProviders:[{ provide: ControlContainer, useExisting: FormGroupDirective }]