Support us .Net Basics C# SQL ASP.NET Aarvi MVC Slides C# Programs Subscribe Download

Angular dynamic forms tutorial

Suggested Videos
Part 18 - Angular reactive forms cross field validation | Text | Slides
Part 19 - Angular formarray example | Text | Slides
Part 20 - Creating formarray of formgroup objects in Angular | Text | Slides

In this video, we will discuss generating FormGroups and FormControls dynamically at runtime


Here is what we want to do. Every time we click "Add Skill" button we want to generate another set of skill related form controls (i.e Skill, Experience & Proficiency).


angular dynamic forms tutorial

This is continuation to our previous video, Part 20. Please watch Part 20 from Angular 6 tutorial before proceeding.

Step 1 : Include Add Skill button

Place the following HTML inside the <div> element with class well. Notice the click event is bound to addSkillButtonClick() method. We will create this method in the component class next.

<div class="form-group">
  <div class="col-md-offset-2 col-md-4">
    <button type="button" class="btn btn-primary" (click)="addSkillButtonClick()">
      Add Skill
    </button>
  </div>
</div>

Step 2 : Include addSkillButtonClick() method in the component class
  • From the root FormGroup "employeeForm" get a reference to the skills FormArray. Notice we have passed the name of the FormArray (skills) as a parameter to the get() method.
  • The get() method returns the FormArray as an AbstractControl. We know it's a FormArray so we are type casting it to FormArray.
  • We are then calling the push() method of the FormArray to push a new FormGroup into the FormArray
  • The push() method calls addSkillFormGroup() method which returns an instance of the FormGroup with the 3 skill related form controls (skill, experience & proficiency)

addSkillButtonClick(): void {
  (<FormArray>this.employeeForm.get('skills')).push(this.addSkillFormGroup());
}

Step 3 : Loop over "skills" FormArray to dynamically generate the HTML input elements.
  • Notice we are using *ngFor structural directive to loop over the "skills" FormArray
  • For each FormGroup in the FormArray, the respective HTML input elements (skill, experience & proficiency) will be generated
  • We are also binding the formGroupName directive to the loop variable i
  • Since we are binding to a variable do not forget to use square brackets around [formGroupName] directive, otherwise you will get a run-time error - Cannot find control with path: 'skills -> i'
<div formArrayName="skills"
     *ngFor="let skill of employeeForm.get('skills').controls; let i = index">
  <div [formGroupName]="i">
      <!-- Skill Name Label & Form Control HTML
      Experience Label & Form Control HTML
      Proficiency Label & Form Control HTML -->
  </div>
</div>

At the moment there are several problems with the dynamically generated HTML input elements

  • The dynamically generated HTML input elements have the same id. For example, all the "skillName" textboxes have the same id "skillName". Not only the id, even the for attribute value of the labels is also the same.
  • As a result when we click on a label of an input element, the wrong textbox receives focus.
  • Also, the validation is broken.
  • We will discuss fixing these issues in our next upcoming videos.
angular 6 tutorial for beginners

10 comments:

  1. Hello sir ,
    Please help me sir,I have a problem, i have written web api for fetching employee information from sql server. I am getting correct result for calling api to get employees or employee by ID. but when i call POST or PUT it gives me error -----
    Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:54074/api/values/?id=1. (Reason: CORS preflight channel did not succeed).[Learn More]
    Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:54074/api/values/?id=1. (Reason: CORS request did not succeed).

    I have added required configuration (that u have told in some api videos for cross origine) in web config file
    Please help me.

    Thank you,
    Umakant Jadhav

    ReplyDelete
  2. Please use the CORS extension for time being.You can find the CORS extension in google chrome extensions.It's related to cross origin problem not issue with your code.

    ReplyDelete
  3. I tried using square bracket for formGroupName in div tag, but getting error as FormGroupName is not a property of div

    ReplyDelete
  4. deploy a production build
    ERROR in src\app\employee\create-employee.component.html(81,37): : Property 'controls' does not exist on type 'AbstractControl'.

    ReplyDelete
  5. error : when deploy a production build : ng build --prod --base-href /empang/

    ERROR in src\app\employee\create-employee.component.html(81,37): : Property 'controls' does not exist on type 'AbstractControl'.

    81. formArrayName="skills" *ngFor="let skill of employeeForm.get('skills').controls; let i = index">


    ReplyDelete
  6. Me too :(
    Property 'controls' does not exist on type 'AbstractControl'

    ReplyDelete
    Replies
    1. use formGroup.get('commissionDetails')['controls']
      instead of formGroup.get('commissionDetails').controls

      Delete
  7. Found the solution!
    Create a get method in the ts and return as a FormArray.
    then do xyz.controls in the html.

    ReplyDelete
  8. use this employeeForm.get('skills').value it worked for me

    ReplyDelete

It would be great if you can help share these free resources