25
Angular Template form control in separate reusable component
This article is all about angular Template driven forms in angular. But When working with angular forms we have two approach to select
1. Template Driven Form
2. Reactive Forms
So, Template driven forms are very useful when forms structure is pretty small and do not need more dynamic form creation with model. There are some terms of angular template forms..
- ngForm
- name property for control.
- ngModel
- FormsModule
We need to import FormsModule
inside app.module.ts
file of angular. By importing this module we can use and can enable feature of it inside our component.
import { FormsModule } from '@angular/forms';
@NgModule({
imports: [ FormsModule ],
})
export class AppModule{}
By looking into official angular documentation we can find what is ngForm.
The NgForm directive creates a top-level FormGroup instance and binds it to a <form>
element to track aggregated form value and validation status. As soon as you import FormsModule, this directive becomes active by default on all <form>
tags.
< form #heroForm="ngForm" >
<!-- All forms will be generated within this area -->
< /form >
Angular NgModel is an inbuilt directive that creates a FormControl
instance from the domain model and binds it to a form control element. The ngmodel
directive binds the value of HTML controls (input, select, textarea) to application data.
< input type="text" #firstName="ngModel">
<!-- So whatever we write inside input box, angular bind it inside fristName model of component.
It is necessary to bind name property with input element in order to differentiate control model with other input element inside ngForm. So what ever we give name it will act as ngForm Model.
< input type="text" #firstName="ngModel" [(ngModel)]="nameModel" name="firstName" >
So by visiting above terms now lets see complete template of template driven forms. If we want input to be required field of form then we can use required attribute of forms for input element.
<form #userRegistrationForm="ngForm">
< input required type="text" [(ngModel)]="userForm.firstName" name="firstName" >
</form>
So when we submit form then we have form model like below
{ firstName : '' }
Up to now its refresher of angular forms but in this article I want to make child component of input to reuse inside our application inside multiple times with many ngForm Groups. To do this first lets see about main template of component.
<form #heroForm="ngForm" class="container" (ngSubmit)="onSubmitValidator(heroForm.value)">
<div id="parent" *ngFor="let i of [0,1,2]" >
<app-child [id]="i+1" [name]="i+1" ></app-child>
</div>
<hr>
{{heroForm.value | json}}
<hr>
<div>
<app-button-submit></app-button-submit>
</div>
</form>
see above app-child
component is our custom component and is placed inside ngFor loop. Now lets see whats inside app-child component.
First step we need to provide dependency to app-child viewProviders array.
viewProviders: [{ provide: ControlContainer, useExisting: NgForm }]
This will make sure that ControlContainer is provided by angular then we need to use existing ngForm. First ControlContainer is basic class of form used for providing parent form to child, and we use useExisting of ngForm, so we tell angular that use only current parent formGroup with this component.
<div class="form-group">
<label [for]="Name">Name</label>
<input required #templatInputRef="ngModel" type="text" class="form-control"
[id]="inputId" [name]="inputName" [(ngModel)]="vname" (keyup)="onChange(templatInputRef)">
{{vname}}
<div class="alert alert-danger" [hidden]="templatInputRef.valid || templatInputRef.pristine">
Name is required
</div>
</div>
<hr>
So this way we provide relation between parent ngForm to child component. So each child component has their own name and model binds with. so when parent inside ngFor we create multiple elements then each element treated ad separate form element.
Now, This way we will also build submit component reusable too!
@Component({
selector: 'app-button-submit',
templateUrl: './button-submit.component.html',
styleUrls: ['./button-submit.component.css'],
providers : [{provide : ControlContainer, useExisting : NgForm}]
})
export class ButtonSubmitComponent {
constructor(private control : NgForm) { }
}
<button type="submit" class="btn btn-success"
[disabled]="!control.form.valid">Submit
</button>
In above we inject ngForm directly to submit component, so what ever parent ngForm is now inside our child submit component and acts as separate component too. You can find demo in below..
25