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

You can support me. Please click below image. Thank You.

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

  1. ngForm
  2. name property for control.
  3. ngModel
  4. FormsModule

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{}

ngForm

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 >

ngModel

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.

name

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.

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

You can support me

25