DEV Community

GaurangDhorda
GaurangDhorda

Posted on

1 2

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

SurveyJS custom survey software

Build Your Own Forms without Manual Coding

SurveyJS UI libraries let you build a JSON-based form management system that integrates with any backend, giving you full control over your data with no user limits. Includes support for custom question types, skip logic, an integrated CSS editor, PDF export, real-time analytics, and more.

Learn more

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay