irossimoline/angular4-material-table

How to use this code with reactive forms and form Arrays ?

Closed this issue · 3 comments

Hello,
I loved the code, it will be really helpful if you can guide me on how to implement this kind of table with reactive forms and FormArray.
let's say that the below method is responsible for creating the form

createForm(){
 this.entryForm = this.formBuilder.group({
        date: ['', [Validators.required]],
        notes: [''],
        items: this.initItems()
      
      });
}

I need to manage the Items through an editable table, at the beginning the table must have two empty rows:

 initItems(){
    var formArray = this.formBuilder.array([]);
 
    for(let i=0 ; i< 2 ; i++){
      formArray.push(this.formBuilder.group({
        name: ['', [Validators.required]],
        age: ['', [Validators.required]],
      }));
    }
    
  return formArray;
  }

The Html markup of the table should be drawn according to the data of the items formArray.
to add a row to the table, I need to add a row to the formArray first:

addNewItem(name: string , age: number){
 var controls = <FormArray>this.entryForm.controls['items'];
  var formGroup= this.fb.group({
      name: [name, [Validators.required]],
       age: [age, [Validators.required]],
    });
    controls.push( formGroup);
}

the same for edit and remove, I need to remove the row form the FormArray.
I just can't Imagine how can I link this code to yours?

Hi @furqanaa, I have been thinking a while about your needings, and I have few questions:

  • Why do you need to implement it with FormArray? The reason behind not implementing the table with FormArray was because it doesn't make much sense to validate all rows in table, but each row when confirming the changes.
  • why do you need to have the empty rows on the table? Does have sense to have empty values when the fields are required?

In the implementation of ValidatorService you can instance the FormGroup with default values.

Thanks for the quick response.
Indeed, I need to add two rows by default because I'm implementing a financial entry which must have two items at least.
also, I need to use the FormArray because I want to validate all the rows together (business constraints).
I couldn't build the material-table based on the FormArray structure and I end up using a regular HTML table plus material table's styles:

 <table class="mat-table example-container mat-elevation-z8" > 
            <tr class="mat-header-row ">
              <th class="mat-header-cell" >Account</th>              
              <th class="mat-header-cell" >Credit</th>
              <th class="mat-header-cell">Debit</th>
              <th class="mat-header-cell" >Notes</th>         
              <th class="mat-header-cell">
                  <button mat-icon-button color="accent" type="button" title="new item" (click)="addNewItem()" >
                      <mat-icon>add</mat-icon>
                  </button>              
              </th>
            </tr>
            <tr class="mat-row" formArrayName="items" *ngFor="let item of entryForm.get('items').controls; let i = index;">
              <ng-container  [formGroupName]="i">
                  <td class="mat-cell">

                      <mat-form-field appearance="outline" floatLabel="always" class="example-full-width table-form-field table-form-field-right" >
                          <input type="text" placeholder="Search for an account" matInput formControlName="account" [matAutocomplete]="account">
                          <mat-autocomplete #account="matAutocomplete" [displayWith]="displayFn.bind(this)">
                            <mat-option *ngFor="let option of filteredOptions | async " [value]="option">
                              {{ option.name }}
                            </mat-option>
                          </mat-autocomplete>
                          <mat-error *ngIf="item.controls['account'].errors?.required ">You must enter a value</mat-error>
                        </mat-form-field>
                  </td>
                  <td class="mat-cell">

                        <mat-form-field appearance="outline" floatLabel="always" >
                            <input matInput #credit maxlength="30"  formControlName="credit">
                            <mat-icon matSuffix>attach_money</mat-icon>
                            <mat-hint align="end">{{credit.value?.length || 0}}/30</mat-hint>
                            <mat-error *ngIf="item.controls['credit'].errors?.required && (item.controls['credit'].dirty || item.controls['credit'].touched)">You must enter a value</mat-error>
                          </mat-form-field>
                 
                  </td>
                  <td class="mat-cell">
                      <mat-form-field appearance="outline" floatLabel="always" >
                          <input matInput #debit maxlength="30"  formControlName="debit">
                          <mat-icon matSuffix>attach_money</mat-icon>
                          <mat-hint align="end">{{debit.value?.length || 0}}/30</mat-hint>
                          <mat-error *ngIf="item.controls['debit'].errors?.required && (item.controls['debit'].dirty || item.controls['debit'].touched)">You must enter a value</mat-error>
                        </mat-form-field>
                  </td>

                  <td class="mat-cell">
                      <mat-form-field appearance="outline" floatLabel="always" >
                          <input matInput #notes maxlength="30" formControlName="notes">
                          <mat-icon matSuffix>short_text</mat-icon>
                          <mat-hint align="end">{{notes.value?.length || 0}}/60</mat-hint>
                        </mat-form-field>
                  </td>
             
            
                  <td class="mat-cell">
                      <button mat-icon-button color="primary" type="button" title="delete item" (click)="removeItem(i)" >
                          <mat-icon>delete</mat-icon>
                      </button>   
                  
                  </td>
              
                  
              </ng-container>
                
            </tr>

          </table>

Hi @furqanaa,

Sorry for the delay this time. Considering that you have different needs than the package could provide, I can suggest you do one of the following:
-Extend package's functionality (fork it on Github), and change it to fit your needs. There is a currently opened issue where the package is needed to meet more specific needs, and it's going to be extended. Feel free to check it.
-Do it as you did, and use the basic angular table structure.

I'd follow the first one if this will be used in many places, or if you want to have it "packaged" (logic defined more explicitly or/and in a specific place). On the other hand, if that previous points are not that important, following the second option is the best from my point of view.

As you have found a solution I'll to close this issue. If you have any additional question or issue, please feel free to open a new issue.

Regards.