Javascript 从数组中获取同级抽象控件-自定义验证

Javascript 从数组中获取同级抽象控件-自定义验证,javascript,angular,angular-reactive-forms,angular-abstract-control,angular-custom-validators,Javascript,Angular,Angular Reactive Forms,Angular Abstract Control,Angular Custom Validators,我有一个角度的接触形式,用反应形式。表单包含firstName、lastName和地址数组。每个地址表单组都包含一个复选框,如果选中该复选框,则需要强制验证状态文本框以及最小和最大字符长度 我已经编写了一个自定义验证器,即stateValidator,我试图将同级元素作为强制元素,但无法获取控件 我尝试了以下方法 control.root.get'isMandatory';-它返回空值 控件。父控件。获取“isMandatory”;-这是一个例外 我在stackoverflow中找到了一些链接,

我有一个角度的接触形式,用反应形式。表单包含firstName、lastName和地址数组。每个地址表单组都包含一个复选框,如果选中该复选框,则需要强制验证状态文本框以及最小和最大字符长度

我已经编写了一个自定义验证器,即stateValidator,我试图将同级元素作为强制元素,但无法获取控件

我尝试了以下方法

control.root.get'isMandatory';-它返回空值 控件。父控件。获取“isMandatory”;-这是一个例外 我在stackoverflow中找到了一些链接,但是没有可用的答案,一些答案没有给出解决方案,例如上面的代码:control.root.get'isMandatory';我从一个视频教程中得到了这个,但没有任何效果

StackBlitz中提供了完整的工作源代码:

app.component.ts

import { Component } from '@angular/core';
import { FormBuilder, FormGroup, FormArray, Validators, AbstractControl } from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular';
  public userForm: FormGroup;

  constructor(private _fb: FormBuilder) {
    this.userForm = this._fb.group({
      firstName: [],
      lastName: [],
      address: this._fb.array([this.addAddressGroup()])
    });
  }

  private addAddressGroup(): FormGroup {
    return this._fb.group({
      street: [],
      city: [],
      state: ['', this.stateValidator],
      isMandatory: [false, [Validators.required]]
    });
  }

  get addressArray(): FormArray {
    return <FormArray>this.userForm.get('address');
  }

  addAddress(): void {
    this.addressArray.push(this.addAddressGroup());
  }

  removeAddress(index: number): void {
    this.addressArray.removeAt(index);
  }

  stateValidator(control: AbstractControl): any {
        if(typeof control === 'undefined' || control === null 
        || typeof control.value === 'undefined' || control.value === null) {
            return {
                required: true
            }
        }

        const stateName: string = control.value.trim();
        const isPrimaryControl: AbstractControl = control.root.get('isMandatory');

        console.log(isPrimaryControl)

        if(typeof isPrimaryControl === 'undefined' || isPrimaryControl === null||
        typeof isPrimaryControl.value === 'undefined' || isPrimaryControl.value === null) {
            return {
                invalidFlag: true
            }
        }

        const isPrimary: boolean = isPrimaryControl.value;

        if(isPrimary === true) {
            if(stateName.length < 3) {
                return {
                    minLength: true
                };
            } else if(stateName.length > 50) {
                return {
                    maxLength: true
                };
            }
        } else {
            control.setValue('');
        }

        return null;
    }
}
app.component.html

<form class="example-form" [formGroup]="userForm">
  <div>
    <mat-card class="example-card">
      <mat-card-header>
        <mat-card-title>Users Creation</mat-card-title>
      </mat-card-header>
      <mat-card-content>
        <div class="primary-container">
          <mat-form-field>
            <input matInput placeholder="First Name" value="" formControlName="firstName">
          </mat-form-field>
          <mat-form-field>
            <input matInput placeholder="Last Name" value="" formControlName="lastName">
          </mat-form-field>
        </div>
        <div formArrayName="address">
          <div class="address-container" *ngFor="let group of addressArray.controls; let i = index;"
            [formGroupName]="i">
            <fieldset>
              <legend>
                <h3>Address: {{i + 1}}</h3>
              </legend>
              <mat-checkbox formControlName="isMandatory">Mandatory</mat-checkbox>
              <div>
                <mat-form-field>
                  <input matInput placeholder="Street" value="" formControlName="street">
                </mat-form-field>
                <mat-form-field>
                  <input matInput placeholder="City" value="" formControlName="city">
                </mat-form-field>
                <mat-form-field>
                  <input matInput placeholder="State" value="" formControlName="state">
                </mat-form-field>
              </div>
            </fieldset>
          </div>
        </div>
        <div class="form-row org-desc-parent-margin">
          <button mat-raised-button (click)="addAddress()">Add more address</button>
        </div>
      </mat-card-content>
    </mat-card>
  </div>
</form>
<mat-card class="pre-code">
  <mat-card-header>
    <mat-card-title>Users Information</mat-card-title>
  </mat-card-header>
  <mat-card-content>
    <pre>{{userForm.value | json}}</pre>
  </mat-card-content>
</mat-card>
请帮助我如何在自定义验证器方法中获取兄弟抽象控件

我尝试了下面两个答案中指定的代码

stateValidator(control: AbstractControl): any {
let mandatory:boolean=false;
if(control.parent){
  console.log('control',<FormGroup>control.parent.controls.isMandatory.value);
  mandatory=<FormGroup>control.parent.controls.isMandatory.value;
}
    if((typeof control === 'undefined' || control === null 
    || typeof control.value === 'undefined' || control.value === null)&& mandatory) {
      debugger;
        return {
            required: true
        }
    }

    const stateName: string = control.value.trim();
    let isPrimaryControl: AbstractControl=null;
    if(control.parent){
     isPrimaryControl=<FormGroup>control.parent.controls.isMandatory;
    console.log(isPrimaryControl)
    }
    if(typeof isPrimaryControl === 'undefined' || isPrimaryControl === null||typeof isPrimaryControl.value === 'undefined' || isPrimaryControl.value === null) {
        return {
            invalidFlag: true
        }
    }

    const isPrimary: boolean = isPrimaryControl.value;

    if(isPrimary === true) {
        if(stateName.length < 3) {
            return {
                minLength: true
            };
        } else if(stateName.length > 50) {
            return {
                maxLength: true
            };
        }
    } else {
        control.setValue('');
    }

    return null;
}
它抛出了一个错误:太多的递归。请帮助我解决这个问题。

您可以像这样从表单控件中获取isMandatory的值,我已将您的stateValidator方法更改为基本上将控件类型转换为具体的子类,然后从控件数组中获取formControls

您可以像这样从表单控件中获取isMandatory的值,我已经将您的stateValidator方法更改为基本上将控件类型转换为具体的子类,然后从控件数组中获取formControls


您可能需要将父级强制转换为FormGroup,请尝试使用:


您可能需要将父级强制转换为FormGroup,请尝试使用:



我认为如果我使用control.parent.controls会导致页面崩溃,也就是说,在实际应用中,它会抛出一个异常。它抛出的异常是什么?在下面的StackBlitz中尝试你的代码,它会导致窗口崩溃。我得到一个错误:递归太多我认为如果我使用control.parent.controls会导致页面崩溃,也就是说。,在实际应用中,它会抛出一个异常它抛出的异常是什么?在下面的StackBlitz中尝试你的代码,它会使窗口崩溃。我得到一个错误:递归太多如果你必须放入包含多个FormControl的验证,考虑将验证器添加到Frand组中,而不是单个Falm控件。@ SaskupTa-我的主要目的是如何将兄弟控件控制在另一个控件上。但是,根据您访问control.parent的位置,可能存在值未定义的可能性,因此您必须进行适当的检查。我遇到了一个错误:如果我添加代码isPrimaryControl=control.parent.get'isMandatory'注释control.SetValues,则递归过多。如果您必须进行包含多个FormControl的验证,考虑将验证器添加到Frand组中,而不是单个Falm控件。@ SaskupTa-我的主要目的是如何将兄弟控件控制在另一个控件上。但是,根据您访问control.parent的位置,可能存在值未定义的可能性,因此您必须进行适当的检查。我遇到了一个错误:如果我添加代码isPrimaryControl=control.parent.get'isMandatory'注释control.SetValueIt给出控制台错误错误:control.parent未定义在chrome控制台中尝试使用调试器在stateValidator函数中,它给出了父组,我还能够获得isMandatory控件。您能看看现在看到的StackBlitz中的代码吗。创建控件时,该控件未附加到父控件,因此会出现错误。只需进行if control.parent检查,其他一切都应该正常工作。分叉代码时,您需要对control.setValue进行注释,否则您将无法在控件中键入任何内容。可能需要在单击复选框时进行一些小的调整,以进行正确的验证。它会给出一个控制台错误:control.parent未定义在chrome控制台中尝试使用stateValidator函数中的调试器,它给了父组,我也能得到isMandatory控件。你能看看StackBlitz中的代码吗。创建控件时,该控件未附加到父控件,因此会出现错误。只需进行if control.parent检查,其他一切都应该正常工作。分叉代码时,您需要对control.setValue进行注释,否则您将无法在控件中键入任何内容。可能需要在单击复选框时进行一些小的调整,以进行适当的验证。
stateValidator(control: AbstractControl): any {
let mandatory:boolean=false;
if(control.parent){
  console.log('control',<FormGroup>control.parent.controls.isMandatory.value);
  mandatory=<FormGroup>control.parent.controls.isMandatory.value;
}
    if((typeof control === 'undefined' || control === null 
    || typeof control.value === 'undefined' || control.value === null)&& mandatory) {
      debugger;
        return {
            required: true
        }
    }

    const stateName: string = control.value.trim();
    let isPrimaryControl: AbstractControl=null;
    if(control.parent){
     isPrimaryControl=<FormGroup>control.parent.controls.isMandatory;
    console.log(isPrimaryControl)
    }
    if(typeof isPrimaryControl === 'undefined' || isPrimaryControl === null||typeof isPrimaryControl.value === 'undefined' || isPrimaryControl.value === null) {
        return {
            invalidFlag: true
        }
    }

    const isPrimary: boolean = isPrimaryControl.value;

    if(isPrimary === true) {
        if(stateName.length < 3) {
            return {
                minLength: true
            };
        } else if(stateName.length > 50) {
            return {
                maxLength: true
            };
        }
    } else {
        control.setValue('');
    }

    return null;
}
if(control.parent) {
    (<FormGroup>control.parent).get('isMandatory')
}