Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 creating reactive forms with nested components

My requirement is that I need to create a form with nested components. I am creating components for each form field means for textbox there will be one component, for radio button there will be another component like wise.
<form [formGroup]="myForm">
<textbox-component></textbox-component>
<radioButton-component></radioButton-component>
</form>

And I want to use Reactive forms for creating this form as I want my html to be untouched and have my form validations through typescript only.

But I cant find any solution how can we have reactive forms nested with components.

like image 770
Mahesh Saibalwar Avatar asked Mar 01 '17 12:03

Mahesh Saibalwar


People also ask

Can we have nested forms in Angular?

Nested Forms will allow us to create the array of objects for a single field and this hierarchy goes on. (i.e) A single object can have a number of objects inside of it, and we can achieve it in Reactive forms through the concept of “Form Array”.

How do you create a Reactive form object inside a component class?

To build reactive forms, first, we need to import ReactiveFormsModule . We then create the Form Model in component class using Form Group, Form Control & FormArrays. Next, we will create the HTML form template and bind it to the Form Model.

What are the two ways to build forms in Angular 2?

Angular provides two different approaches to handling user input through forms: reactive and template-driven.


2 Answers

After my research & experiments I found one answer to my question, so answering it myself. If it saves someone's time then I will be happy.

If you want to create reactive forms with nested components then you can do as below

Here I am creating a form with two nested components one for textbox & other for radio button

Your parent component can be like this

<form [formGroup]="myForm">     <child-textbox-component [parentFormGroup]="myForm">     </child-textbox-component>     <child-radio-button-component [parentFormGroup]="myForm">     </child-radio-button-component> </form> 

We are passing FormGroup object as input to child components which has been created in the parent component as input to the child components, they will use this FormGroup object in their component to design specific control of the class

Your child components will be like this

child-textbox-component

<div class="form-group" [formGroup]="parentFormGroup">   <label>     {{control.caption}}   </label>   <input class="form-control" type="text" [title]="control.toolTip"      [attr.maxlength]="control.width" [name]="control.name"     [value]="control.defaultValue" [formControlName]="control.name"/> </div> 

child-radio-button-component

<div class="form-group" [formGroup]="parentFormGroup">   <label>     {{control.caption}}   </label>   <div>       <label *ngFor="let value of control.values; let idx = index"         class="radio-inline" [title]="control.tooltip">         <input type="radio" [name]="control.name" [formControlName]="control.name"/>         {{ value }}       </label>   </div> </div> 

Here control is the model class holding data to be displayed for these child components.

This way you can have your form to be generated using nested components, so that you need not have your form (can say large form) in single component. You can break it down to as many sub components & form will be easy to create & maintain also using reactive forms of angular 2. You can also easily add validations too.

I followed these links before answering this

  1. something similar on stackoverflow

  2. angular 2 dynamic forms

like image 93
Mahesh Saibalwar Avatar answered Sep 28 '22 02:09

Mahesh Saibalwar


Additional note to Mhesh's answer, you can build this sames solution without injecting [parentFormGroup] in the HTML. You can do this by following this Stack Overflow post on reusable form groups.

This is really nice.

Example

To take the existing solution, you can do the same thing, except:

Your parent component can be like this, without any additional parameters passed in

<form [formGroup]="myForm">     <child-textbox-component></child-textbox-component>     <child-radio-button-component></child-radio-button-component> </form> 

Note additionally you can set formgroups like this:

<form [formGroup]="myForm">     <child-textbox-component></child-textbox-component>     <child-radio-button-component formGroupName="myGroup"></child-radio-button-component> </form> 

child-textbox-component

<div class="form-group" [formGroup]="controlContainer.control">   <label>     {{control.caption}}   </label>   <input class="form-control" type="text" [title]="control.toolTip"      [attr.maxlength]="control.width" [name]="control.name"     [value]="control.defaultValue" [formControlName]="control.name"/> </div> 

To enable this you want to inject a ControlContainer into your @Component

@Component({     moduleId: `MODULE_ID_HERE`,     selector: "child-textbox-component",     templateUrl: "childTextbox.component.html", }) export class ChildTextboxComponent {     constructor(private controlContainer: ControlContainer, OTHER_PARAMETERS) {     } } 
like image 29
Stormswept Avatar answered Sep 28 '22 02:09

Stormswept