Angular FormArray 中的自定义验证(比例总和必须为 100%)

Custom Validations in Angular FormArray (Sum of proportion must be 100%)

我在 angular 中创建了一个 formArray 来表示 Nominee 的分布,它有两个字段 Name 和 Proportion。加号按钮 (+) 添加新行,(X) 按钮删除当前行。现在我想编写验证代码,使比例列的总数必须为 100%(无论它包含多少被提名人的名字)
例如
无姓名比例
1 安迪 100
(比例之和为100)
------------
例 2
无姓名比例
1 安迪 60
2 Bruce 40
(比例之和为100)
----------
例 3
无姓名比例
1 安迪 60
2 布鲁斯 20
3 Ciao 20
(比例之和为100)
----------

这是我的component.html代码

<h5>Nominees</h5>
                <div class="row">
                    <form novalidate [formGroup]="FormNominees">

                        <div clas="col-xs-12 form-group marL40">
                            <div formGroupName="itemRows">
                                <ng-container *ngIf="FormNominees.controls.itemRows!=null">
                                    <div *ngFor="let itemrow of FormNominees.controls.itemRows.controls; let i = index"
                                        [formGroupName]="i">
                                        <div class="row">
                                            <mat-form-field
                                                class="example-full-width d-block input-small-size col-sm-2.4"
                                                appearance="outline">
                                                <input matInput placeholder="Name" formControlName="name">
                                                <mat-error *ngIf="f9.name.touched && f9.name.errors?.required">It is mandatory
                                                </mat-error>
                                                <mat-error *ngIf="f9.name.touched && f9.name.errors?.pattern">Can only contain characters.
                                                </mat-error>
                                            </mat-form-field>

                                            <mat-form-field
                                                class="example-full-width d-block input-small-size col-sm-2.4"
                                                appearance="outline">
                                                <input matInput placeholder="Relationship"
                                                    formControlName="relationship">
                                                    <mat-error *ngIf="f9.relationship.touched && f9.relationship.errors?.required">It is mandatory
                                                    </mat-error>
                                            </mat-form-field>
                                            
                                            <mat-form-field
                                                class="example-full-width d-block input-small-size col-sm-2.4"
                                                appearance="outline">
                                                <mat-select formControlName="gender" placeholder="Gender">
                                                    <mat-option value="Male">Male</mat-option>
                                                    <mat-option value="Female">Female</mat-option>
                                                    <mat-option value="Other">Other</mat-option>
                                                </mat-select>
                                                <mat-error *ngIf="f9.gender.touched && f9.gender.errors?.required">It is mandatory
                                                </mat-error>
                                            </mat-form-field>

                                            <mat-form-field
                                                class="example-full-width d-block input-small-size col-sm-2.4"
                                                appearance="outline">
                                                <input matInput placeholder="phone" formControlName="phone">
                                                <mat-error *ngIf="f9.phone.touched && f9.phone.errors?.required">It is mandatory
                                                </mat-error>
                                                <mat-error *ngIf="f9.phone.touched && f9.phone.errors?.pattern">Can only contain numbers.
                                                </mat-error>
                                            </mat-form-field>

                                            <mat-form-field
                                                class="example-full-width d-block input-small-size col-sm-2.4"
                                                appearance="outline">
                                                <input matInput placeholder="Proportion"
                                                    formControlName="gratuityProportion">
                                                     <mat-error *ngIf="f9.gratuityProportion.touched && f9.gratuityProportion.errors?.required">It is mandatory
                                                    </mat-error>
                                                    <mat-error *ngIf="f9.gratuityProportion.touched && f9.gratuityProportion.errors?.pattern">Can only contain numbers.
                                                    </mat-error> 
                                                    <mat-error *ngIf="f9.gratuityProportion.touched && f9.gratuityProportion.errors?.proportionValidator">Total must be 100%.
                                                    </mat-error> 

                                            </mat-form-field>
                                            
                                            <div class="col-sm-2.4">
                                                <button (click)="deleteRow(i)" class="btn btn-danger">x</button>
                                                <!-- </div>
                                            <div class="form-group"> -->
                                                <button type="button" (click)="addnewRow()"
                                                    [disabled]="FormNominees.invalid" 
                                                    class="btn btn-primary">+</button>
                                            </div>
                                        </div>
                                    </div>
                                </ng-container>
                            </div>
                        </div>

                    </form>
                </div> <br>

这是我的component.ts代码

        import { proportionValidator } from './proportion.validator';
        @Component({
          selector: 'app-component',
          templateUrl: './component.component.html',
          styleUrls: ['./component.component.scss']
        })
        export class GratuityComponent implements OnInit {
      FormNominees: FormGroup;
      TotalRow: number;
      itemFB: any;
    
    constructor(private fb: FormBuilder) {
    
   }
ngOnInit(): void {

this.FormNominees = this.fb.group({
      itemRows: this.fb.array([this.initItemRow()])
    });
  initItemRow() {
    this.itemFB =  this.fb.group({
      name: ['', [Validators.required, Validators.pattern('[a-zA-Z0-9. ]*' )]],
      relationship: ['', Validators.required],
      phone: ['', [Validators.required, Validators.pattern('[a-zA-Z0-9. ]*' )]],
      gratuityProportion: ['', [Validators.required, Validators.pattern('^[0-9]*$'), proportionValidator] ],
      gender:['', Validators.required],
      
      employeeUniqueId: '00000001-0001-0001-0001-000000000001'
    })
    return this.itemFB;
  }

  addnewRow() {
    const control = <FormArray>this.FormNominees.controls['itemRows'];
    control.push(this.initItemRow())
  }

  deleteRow(index: number) {
    const control = <FormArray>this.FormNominees.controls['itemRows'];
    // control.push(this.initItemRow())
    if (control != null) {
      this.TotalRow = control.value.length;
    }
    if (this.TotalRow > 1) {
      control.removeAt(index);
    } else {
      alert('One record is mandatory');
      return false;
    }
  }
  get f9() {return this.itemFB.controls;}

}
    
    }

现在,我的问题是我应该在proportion.validator.ts中写什么代码来实现这个条件?

Straight from the docs:

const arr = new FormArray(
  [
    new FormControl('Nancy'),
    new FormControl('Drew')
  ], 
  {
   validators: myValidator //<- this is where your proportion validator goes
  }
);

在你的情况下,它看起来像这样:

    this.FormNominees = this.fb.group({
      itemRows: this.fb.array(
        [
          this.initItemRow()
        ],
        { 
           validators: proportionValidator 
        }
      )
    });