angular表单踩坑之二

一:如何实现表单项blackList的toggle为true时,显示limitNumber和limitDay提交表单时这两个选项为必填项,如果toggle为false,则无需校验这两个字短。也就是非必填项

this.fm=this.fb.group({
    config:this.fb.group({
       blackList:this.fb.group({
            toggle:[null],
            limitNumber:[null,],
            limitDay:[null,]
     }),

    })
  

}) 

实现

1 页面结构

<div formGroupName="blackList">
                            <nz-form-item>
                                <nz-form-label [nzSpan]="6">Blocklist </nz-form-label>
                                <nz-form-control [nzSpan]="18">
                                    <nz-radio-group formControlName="toggle">
                                        <label nz-radio [nzValue]="true">yes</label>
                                        <label nz-radio [nzValue]="false">No need</label>
                                    </nz-radio-group>
                                </nz-form-control>
                            </nz-form-item>
                            <div class="form_item">
                                <nz-form-item *ngIf="isShowBlockList.value">
                                    <nz-form-label [nzSpan]="6">No-show Limits </nz-form-label>
                                    <nz-form-control [nzSpan]="18">
                                        <div style="width: 200px;">
                                             <input nz-input name="limitNumber" formControlName="limitNumber" type="text" >
                                        </div>  
                                        <div class="err err_tip_box" *ngIf="validateForm.get('config.blackList.limitNumber')?.errors?.['required']">不能为空</div>
                                    </nz-form-control>
                                </nz-form-item> 
                            </div>
                            <div class="form_item">                           
                                    <nz-form-item *ngIf="isShowBlockList.value">
                                        <nz-form-label [nzSpan]="6">Days of No-show Limits </nz-form-label>
                                        <nz-form-control [nzSpan]="18">
                                            <div style="width: 200px;">
                                                <input nz-input name="limitDay"  formControlName="limitDay" type="text" >
                                            </div>
                                            <div class="err err_tip_box" *ngIf="validateForm.get('config.blackList.limitDay')?.errors?.['required']">不能为空</div>
                                        </nz-form-control>
                                    </nz-form-item> 
                            </div>
                    </div>
第三步:定义一个函数,接受toggle的值,当为true时,通过setValidators手动设置其为必填项,否则通过clearValidators()函数清除验证规则
 setBlackListControlValidators(value: boolean): void {
    const limitNumControl = this.validateForm.get('config.blackList.limitNumber');
    const limitDayControl = this.validateForm.get('config.blackList.limitDay');
    if (value === true) {
      limitNumControl?.setValidators([Validators.required]);
      limitDayControl?.setValidators([Validators.required]);
    } else {
      limitNumControl?.clearValidators();
      limitDayControl?.clearValidators();
    }
    limitNumControl?.updateValueAndValidity();
    limitDayControl?.updateValueAndValidity();
  }

二:angular表单多层嵌套的回显问题

表单结构如下

  this.validateForm=this.fb.group({
      storeId: [null],
      storeName:[null],
      status: 0,
      config:this.fb.group({ 
          tableSize:this.fb.group({
              toggle:[null],
              groupSize:this.fb.array([
                this.fb.group({
                  cate:['indoor'],
                  title_en:[''],
                  title_zh:[''],
                  alias_en:[''],
                  alias_zh:[''],
                  tableSize:this.fb.array([]),
                  moreToggle:[null]
                }),                
              ]),
          }),
          geoFencing:this.fb.group({
            geoFencingToggle:[null],
            range:[null],
            latitude:[null],
            longitude:[null]
          }),
          dynamicQRCode:this.fb.group({
            dynamicQRCodeToggle:[null],
            refreshEx:[null]
          }),
          profile:this.fb.group({
            toggle:[null]
          }),
          blackList:this.fb.group({
            toggle:[null],
            limitNumber:[null],
            limitDay:[null]
          }),
          entryToggle:this.fb.group({
            dynamicQRCodeToggle:[null],
            geoFencingToggle:[ null],
          })
      }),
    })

表单的patchValue()只能对一层数据结构有效,而对多层数据结构patchValue()则无效。

正确的办法是对于formarray需要清除之前的数据再进行重新push新的formcontrol,组成新的formarray以后最后进行patch。具体做法如下:

1 通过请求接口得到新的表单项的值

getStoreInfo(id:number){
    this.http.getStoreData({id}).subscribe((res:any)=>{
      console.log("detailres:",res.data)
      if(res.errcode===0){
        this.repatchForm(res.data)
        this.repatchDialogCate(res.data?.config?.tableSize?.groupSize??[])

        this.watchTogles()
        console.log("cat--firn",this.cateForm)
        console.log("groupSize--groupSize",this.groupSize)
      }
    })
  }

2 定义一个repatchForm用于处理整个表单字段

 repatchForm(responseData:any){
    let arr2=this.resetAndGetGroupSize(responseData)            
    this.validateForm.patchValue({
      storeId:responseData.storeId,
      status:responseData.status,
      storeName: responseData.storeName,
      config: {
        tableSize: {
          toggle: responseData?.config?.tableSize?.toggle,
          groupSize: arr2
        },
        geoFencing: {
          geoFencingToggle:responseData?.config?.geoFencing?.geoFencingToggle,
          range: responseData?.config?.geoFencing?.range,
          latitude: responseData?.config?.geoFencing?.latitude,
          longitude: responseData?.config.geoFencing?.longitude,
        },
        dynamicQRCode: {
          dynamicQRCodeToggle:responseData?.config?.dynamicQRCode?.dynamicQRCodeToggle,
          refreshEx:responseData?.config?.dynamicQRCode?.refreshEx
        },
        profile:{
          toggle:responseData?.config?.profile?.toggle,
        },
        blackList:{
          toggle:responseData?.config?.blackList?.toggle,
          limitNumber:responseData?.config?.blackList?.limitNumber,
          limitDay:responseData?.config?.blackList?.limitDay,
        }
      }
    });
    console.log("pathvalue---over",this.validateForm)
  }

3 对于最里层的formarray我们需要重新生成一个新的formarry来替换

//处理会显时table列表数据
  resetAndGetGroupSize(resData:any){

    let arr=resData?.config?.tableSize?.groupSize.map((group: any) => {
      return this.fb.group({
        cate: group.cate,
        title_en: group.title_en,
        title_zh: group.title_zh,
        alias_en:group.alias_en,
        alias_zh:group.title_zh,
        tableSize: this.fb.array(group.tableSize.map((table: any) => {
          return this.fb.group({
            size: [table.size,],
            desc_en: [table.desc_en,[Validators.required]],
            desc_zh: [table.desc_zh,[Validators.required]],
            alias_en: [table.alias_en,],
            alias_zh: [table.alias_zh,],
            preTitle: [table.preTitle,],
            maxPerson: [table.maxPerson,[Validators.required]],
            minPerson: [table.minPerson,[Validators.required,]],
          },{validator:this.minValueValidator()});
        })),
        moreToggle:group.moreToggle
      })
    })
    this.groupSize.clear()
    
    arr.forEach((item:FormGroup)=>{
      this.groupSize.push(item)
    })
    let arr2=arr.map((item:FormGroup)=>{
      return item.value
    })
    return arr2
  }

至此完成了数据的回显

三: 如何实现一个表单项中有两个输入框,分别为最大值和最小值,要求最大值的输入值 必须大于最小值的输入值,即时提醒的效果

<div class="danamic_group_item" >                                                                                                
                                                                                                    <nz-input-number [nzMin]="1" type="number" nz-input   formControlName="minPerson"/>
                                                                                                    <div class="err" *ngIf="table.get('minPerson')?.errors?.['required']&&table.get('minPerson')?.['touched'] ">minPerson不能为空</div>
                                                                                            </div>
                                                                                            <div class="danamic_group_item">
                                                                                                <div>                                                                                               
                                                                                                        <nz-input-number [nzMin]="1" type="number" nz-input   formControlName="maxPerson"/>
                                                                                                    <div class="err" *ngIf="table.get('maxPerson')?.errors?.['required']&&table.get('maxPerson')?.['touched'] ">maxPerson不能为空</div>
                                                                                                </div>
                                                                                            </div>
<div class="err_wrap">
                                                                                            <div>{
    
    {table.value.showErr}}</div> 
                                                                                            <div class="err_item err" *ngIf="(table.get('minPerson')?.errors?.['minValueInvalid'] && table.get('minPerson')?.touched)||(table.get('maxPerson')?.errors?.['maxValueInvalid'] && table.get('maxPerson')?.touched)">
                                                                                                最大值必须大于最小值
                                                                                            </div>
                                                                                        </div>

由于这里的每行的表单项是动态添加的,所以在这里我们在添加的逻辑里做如下验证:

addTable(event:Event){
    event.preventDefault()
    //先找到是indoor还是outdoor的tablsesize
    let curTableSizeArr=this.tableSizeControls(this.actvieTabIndex) as FormArray
    console.log("this.curTableSizeArr",curTableSizeArr)
    if(curTableSizeArr.length>3){
      return
    }else{
        let newdata=this.fb.group({
          size: ["",],
          desc_en:["",[Validators.required]],
          desc_zh: ["",[Validators.required]],
          preTitle:["",[Validators.required]],
          alias_en: ["",],
          alias_zh: [""],
          minPerson: [null,[Validators.required,]],
          maxPerson: [null,[Validators.required,]]
          // minPerson: [null,[Validators.required,]],
          // maxPerson: [null,[Validators.required,]],
        },{validator:this.minValueValidator()})
        newdata.setValidators(this.minValueValidator());
        curTableSizeArr.push(newdata)
        console.log("curTableSizeArr",curTableSizeArr)          
    }
    console.log("this.cateform",this.cateForm)
  
  }

注意这里我们把最大值必须大于最小值的验证的规则放在了fb.group里而不是minperson和maxperson这个formconrol里。其规则定义如下

  minValueValidator():ValidatorFn{
    return (control: AbstractControl): { [key: string]: any } | null => {
      const minValueControl = control.get('minPerson')
      const maxValueControl = control.get('maxPerson')
      console.log("minValue",minValueControl)
      console.log("maxValue",maxValueControl)
      if(minValueControl&&maxValueControl){
        let maxValue=maxValueControl.value
        let minValue=minValueControl.value
        console.log("minValue",minValue)
        console.log("maxValue",maxValue)
        if (minValue&&maxValue&&(maxValue<= minValue)) {
         
           maxValueControl.setErrors({ maxValueInvalid: true });
           console.log("eroor--maxValue<minValue")
           console.log("eroor--contrl",control)
          return { 
         
            maxValueInvalid: true 
          };
        }
      }
      console.log("control",control)
      return null;
    };
  }

回过来再看下我们的dom结构里,

<div class="err_wrap">
                                                                                            <div>{
    
    {table.value.showErr}}</div> 
                                                                                            <div class="err_item err" *ngIf="(table.get('minPerson')?.errors?.['minValueInvalid'] && table.get('minPerson')?.touched)||(table.get('maxPerson')?.errors?.['maxValueInvalid'] && table.get('maxPerson')?.touched)">
                                                                                                最大值必须大于最小值
                                                                                            </div>
                                                                                        </div>

由于minperson和maxperosn的输入框里失去焦点的时候验证的错误提示都是一样的,所以我们把这个错误提示合二为一。

猜你喜欢

转载自blog.csdn.net/baidu_41601048/article/details/133200382