Reactive form for each row of the table

I am using Angular 2 and I want to check the controls on each line separately. But I have no way of doing it. I only want this to be done using reactive forms and not using a boilerplate approach. I want [formGroup] on each <tr>

. Any help would be appreciated. Below is the structure of my code:

<tbody *ngFor="let single of allTeamDetails"                
       [ngClass]="{'alternate-row-color': $even}">
  <tr>
    <td class="td-data first-column">
      <input type="text" class="input-text form-control" 
             [value]="single.first_name">
    </td>
    <td class="td-data second-column">
      <input type="text" class="input-text form-control" 
             [value]="single.last_name">
    </td>
    <td class="td-data third-column">
      <input type="email" class="input-text form-control" 
             [value]="single.email">
    </td>
    <td class="td-data fourth-column">
      <select class="selection-dropdown width-80-percent" 
              [value]="single.user_role">
        <option *ngFor="let singleRole of allUserRole"      
                value="{{singleRole.name}}"> 
                {{setUserRoleAndType(singleRole.name)}}</option>
      </select>
    </td>
    <td class="td-data fifth-column" >
      <input type="password" class="input-text form-control">
    </td>
    <td class="td-data sixth-column" >
      <input type="password" class="input-text form-control">
    </td>
    <td class="td-data save-send-tm-data">
      <button class="btn save-user-details save-sub-account-details"                                                      
              type="button" data-toggle="tooltip" title="Save">
        <i class="fa fa-floppy-o" aria-hidden="true"></i>
      </button>
    </td>
    <td class="td-data save-send-tm-data">
      <button type="button"                                      
              class="btn save-user-details save-sub-account-details"  
              data-toggle="tooltip" title="Send Message"                       
              (click)="openSendMessageModal(single.email)">
        <i class="fa fa-envelope" aria-hidden="true"></i> 
      </button>
    </td>
  <tr>
</tbody>

      

+7


source to share


1 answer


Use formArray

. What you will do is create a formGroup

(master form) containing several smaller ones formGroup

. Each of the smaller groups will be what repeats in yours *ngFor

.

Your form should look something like this:

<!--This is your master form-->
<form [formGroup]="teamForm">
  <!--Use formArray to create multiple, smaller forms'-->
  <div formArrayName="memberDetails">
    <div *ngFor="let single of allTeamDetails; let $index=index">
      <div [formGroupName]="$index">
        <div>
          <!--your field properties of every repeated items-->
          <input placeholder="First Name" type="text" formControlName="firstName" />
        </div>
        <div>
          <input placeholder="Last Name" type="text" formControlName="lastName" />
        </div>
      </div>
    </div>
  </div>
</form>

      

In your component, you can use angular formBuilder

to help create the form.

In your constructor:

  constructor(private formBuilder: FormBuilder) {
    this.teamForm = this.formBuilder.group({
      memberDetails: this.formBuilder.array([])
    });
  }

      



Now you can initialize every property of your repeating models. Then you can customize each validator for each field. Notice the properties in your typescript file that match the properties in HTML. I do all this in ngOnInit

so that properties can be bound to html before they are rendered.

  ngOnInit() {   
    this.teamForm = this.formBuilder.group({
      memberDetails: this.formBuilder.array(
        this.allTeamDetails.map(x => this.formBuilder.group({
          firstName: [x.first_name, [Validators.required, Validators.minLength(2)]],
          lastName: [x.last_name, [Validators.required, Validators.minLength(2)]]
        }))
      )
    })
  }

      

After all this, adding verification messages is very trivial. What are the benefits of doing it this way?

  1. since each instance is now separate formGroup

    , you can customize your validation logic to a very granular level.

  2. As stated above, you can subscribe to every valueChange

    every smaller form, down to every single field. For example, if you want to subscribe to the name change of the first team member, you can do this:

      this.teamForm
       .controls.memberDetails
       .controls[0] //get the first instance!
       .controls.firstName  //get the firstName formControlName
       .valueChange 
       .subscribe(x=>console.log('value changed!))
    
          

  3. If you want to validate the main form, you can do that as well.

Created by plnkr , just for you :)

+19


source







All Articles