DEV Community

GaurangDhorda
GaurangDhorda

Posted on

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.

Alt Text

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{}
Enter fullscreen mode Exit fullscreen mode

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 >
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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" >
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

So when we submit form then we have form model like below

{ firstName : '' }
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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) { }
}
Enter fullscreen mode Exit fullscreen mode
<button  type="submit" class="btn btn-success"
         [disabled]="!control.form.valid">Submit
</button>
Enter fullscreen mode Exit fullscreen mode

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

Alt Text

Discussion (0)