Как проверить таблицу угловых материалов?

Мне сложно проверить таблицу угловых материалов. Мне нужно отключить кнопку сохранения, пока все поля в мат-таблице не будут заполнены.

Я пытался сделать это с помощью форм, как шаблонных, так и реактивных, но у меня ничего не вышло.

Это HTML-код

<mat-card class="card">
  <mat-card-title fxLayout.gt-xs="row" fxLayout.xs="columin">
    <h3>Product Groups Editor</h3>
  </mat-card-title>
  <mat-card-content>
    <div class="data-container">
      <table mat-table [dataSource]="dataSource" matSort>
        <tr mat-header-row *matHeaderRowDef="displayedColumns sticky: true"></tr>
        <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>

        <ng-container matColumnDef="englishName">
          <th mat-header-cell *matHeaderCellDef mat-sort-header class="table-header">English Name</th>
          <td mat-cell *matCellDef="let element">
            <input [disabled]="!element.active" [(ngModel)]="element.englishName" value="{{element.englishName}}">
          </td>
        </ng-container>

        <ng-container matColumnDef="color">
          <th mat-header-cell *matHeaderCellDef class="table-header">Color</th>
          <td mat-cell *matCellDef="let element">
            <input [disabled]="!element.active" [(colorPicker)]="element.color" [style.background]="element.color" />
          </td>
        </ng-container>

        <ng-container matColumnDef="level">
          <th mat-header-cell *matHeaderCellDef mat-sort-header class="table-header">Level</th>
          <td mat-cell *matCellDef="let element">
            <mat-form-field appearance="outline">
              <mat-select placeholder="Level" [disabled]="!element.active" [(ngModel)]="element.groupLevel">
                <mat-option *ngFor="let eachLevel of allGroupLevel" [value]="eachLevel.groupLevelId">
                  {{eachLevel.name}}
                </mat-option>
              </mat-select>
            </mat-form-field>
          </td>
        </ng-container>

      </table>
    </div>
    <div>
      <button id="addButton" (click)="addGroup()" mat-raised-button color="primary">
        <mat-icon>add</mat-icon>Add Group
      </button>
      <button id="saveButton" (click)="saveGroups()" mat-raised-button color="primary">
        <mat-icon>save</mat-icon>Save Groups
      </button>
    </div>
  </mat-card-content>
</mat-card>

Буду очень благодарен, если кто-нибудь сможет помочь.


person Helan Abeysinghe    schedule 31.05.2019    source источник


Ответы (1)


Я не эксперт в Angular и, возможно, сделал это не лучшим образом. Тем не менее, я сделал это, и он заработал, поэтому вот как:

В модуле Component создайте FormControl для каждого элемента управления в HTML. Для таблицы я использовал массив FormGroup, каждая FormGroup имеет элементы управления для одной строки таблицы. Эти элементы управления и группы создаются на основе содержимого MatTableDataSource.

В моем примере кода ниже используется главный объект с парой свойств и массив объектов деталей, каждый из которых имеет 3 свойства.

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators, FormBuilder }   from '@angular/forms';
import { MatTableDataSource }  from '@angular/material';

class Detail {
  id: number;
  name: string;
  value: number;
};

class Master {
  id: number;
  name: string;
  details: Detail[];
};

@Component({
  selector: 'app-master-detail',
  templateUrl: './master-detail.component.html',
  styleUrls: ['./master-detail.component.css']
})
export class MasterDetailComponent implements OnInit {

columnsToDisplay = ['detail_id', 'detail_name', 'detail_value'];

master: Master;
form: FormGroup;
dataSource = new MatTableDataSource([]);
minMasterId = 1;
maxMasterId = 100;
minDetailId = 1;
maxDetailId = 10;

constructor(private fb: FormBuilder) { }

ngOnInit() {

  // Add some code here to get your source data and load it into this.master
  // ...
  // I've added some dummy data to show the principle.
  this.master = {
    id: 1,
    name: "myMaster",
    details: [
      { id: 1, name: "myDetail1", value: 100 },
      { id: 2, name: "myDetail2", value: 200 }
    ]
  };

  // Create the FormControls for the Master.
  this.form = this.fb.group({
      id:      new FormControl(this.master.id, [Validators.required, Validators.min(this.minMasterId), Validators.max(this.maxMasterId)]),
      name:    new FormControl(this.master.name, [Validators.required]),
      details: this.fb.array([])
    });

  // Load the detail objects into the MatTableDataSource.
  this.dataSource.data = this.master.details;

  // For each detail object:
  // 1) Create a FormGroup containing FormControls for all the properties.
  // 2) Add the FormGroup into an array.
  let detailsArray = this.fb.array([]);
  this.dataSource.data.forEach(detail => {
    let formGroupForThisDetail = this.fb.group({
      detail_id:    new FormControl(detail.id,      [Validators.required, Validators.min(this.minDetailId), Validators.max(this.maxDetailId)]),
      detail_name:  new FormControl(detail.name,    [Validators.required]),
      detail_value: new FormControl(detail.value,   [Validators.required, Validators.min(0)]),
    });
    detailsArray.push(formGroupForThisDetail);
  });

  // Add the finished array onto the top-level form.
  this.form.setControl('details', detailsArray);
}

Итак, теперь есть FormControl для каждого свойства каждого объекта в таблице, а FormControl включает валидаторы, соответствующие каждому свойству.

На эти FormControls ссылаются в HTML следующим образом:

<div class="title">
  <h2>View/Edit Master - {{name.value}}</h2>
</div>

<mat-form-field class="master-field-id">
  <input matInput placeholder="Master ID" formControlName="id" type="number" min="{{minMasterId}}" max="{{maxMasterId}}">
</mat-form-field>

<mat-form-field class="master-field-name">
  <input matInput placeholder="Name" formControlName="name">
</mat-form-field>

<mat-table formArrayName="details" [dataSource]="dataSource" matSort>
  <ng-container matColumnDef="detail_id">
    <mat-header-cell *matHeaderCellDef> ID </mat-header-cell>
    <mat-cell *matCellDef="let detail; let rowIndex=index" [formGroupName]="rowIndex">
      <input matInput placeholder="ID" type="number" formControlName="detail_id" min="{{minDetailId}}"
        max="{{maxDetailId}}">
    </mat-cell>
  </ng-container>
  <ng-container matColumnDef="detail_name">
    <mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
    <mat-cell *matCellDef="let detail; let rowIndex=index" [formGroupName]="rowIndex">
      <input matInput placeholder="Name" formControlName="detail_name">
    </mat-cell>
  </ng-container>
  <ng-container matColumnDef="detail_value">
    <mat-header-cell *matHeaderCellDef> Value </mat-header-cell>
    <mat-cell *matCellDef="let detail; let rowIndex=index" [formGroupName]="rowIndex">
      <input matInput placeholder="Value" type="number" formControlName="detail_value" min="0">
    </mat-cell>
  </ng-container>
  <mat-header-row *matHeaderRowDef="columnsToDisplay"></mat-header-row>
  <mat-row *matRowDef="let row; columns: columnsToDisplay"></mat-row>
</mat-table>

<button class="mat-raised-button mat-primary" [disabled]="form.invalid" (click)="onSave()">Save</button>

Кнопка «Сохранить» в нижней части формы изменит свое состояние в зависимости от всех валидаторов для всех свойств (т.е. если ЛЮБОЙ валидатор НЕДЕЙСТВИТЕЛЕН, то форма в целом недействительна и кнопка отключена).

Вам нужно где-то реализовать onSave (), чтобы действительно сохранить.

person Dave C    schedule 20.01.2020