如何解决ExpressionChangedAfterItHasBeenCheckedError错误:'ng-valid'的先前值为'true'。当前值为'false'。

3
有人可以帮我解决这个问题吗?当表单有效时,但是我返回并初始化此组件(将新值推送到 FormArray 中(从零项开始))时会出现此问题。如何找出哪个属性触发了 ng-valid?是数组吗?数组中的单个元素?还是整个 formgroup?
我尝试过ngAfterContentChecked() { this.cdr.detectChanges(); }和changeDetection: ChangeDetectionStrategy.OnPush,并在 push 调用后调用this.cdr.detectChanges()。仍然无法解决。很奇怪,因为它只发生在表单第一次有效,然后我添加一个元素。
@Component({
  selector: 'app-list-other-conditions',
  templateUrl: './list-other-conditions.component.html',
  styleUrls: ['../survey-pmhx.component.scss']
})

export class ListOtherConditionsComponent implements OnInit, OnDestroy {

  @Input()
  formGroup!: FormGroup

  @Input()
  arrayName!: string

  get formArray():FormArray {
    return this.formGroup!.get(this.arrayName)! as FormArray
  }

  addItem() {
    this.formArray.push(this.initItem())
  }
  removeItem(i:number) {
    this.formArray.removeAt(i)
    if (this.formArray.length === 0)
      this.formArray.push(this.initItem())
  }

  public initItem = () : FormGroup =>
    this.fb.group({
      diagnosis: this.fb.control(null, Validators.required),
      year: this.fb.control(null, [Validators.required, CustomValidators.pastYear])
    })

  constructor(private fb: FormBuilder, private readonly cdr: ChangeDetectorRef) { }

  ngOnInit(): void {
    if (this.formArray.length === 0)
      this.addItem();
  }
  }


}


你的代码中的 formGroup 和 arrayName 怎么样?是不是像这样:form: FormGroup = this.fb.group({ arrayName: this.fb.array([]) }); 然后在 HTML 中使用类似这样的表单: <form [formGroup]="form"> <div formArrayName="arrayName"> <div *ngFor="let some of arrayName.controls"> <input /> </div> </div></form> - nestdan
没错,它在父组件中 <form [formGroup]="form" let myform = this.fb.group({ list: this.fb.array([]))})。而这个子组件被称为 <app-list-other-conditions [formGroup]="myform" arrayName="list"></... - user17842237
所以我不明白为什么你要定义arrayName !: string,因为它是一个数组,你可以上传父组件的代码和模板,这样我就可以尝试执行它并查看你的问题。 - nestdan
虽然这个链接可能对您有用:https://www.concretepage.com/angular/angular-formarray-validation - nestdan
如果你上传寺庙的代码,任何人回答你似乎都会更容易。 - nestdan
显示剩余4条评论
1个回答

0
我重复了你代码中在子组件中启动FormGroup的逻辑,尽管我认为这是不必要的,并且它并没有给我带来错误。我还创建了一个子FormGroup并启动了子组件的视图,这似乎也是不必要的,但也没有引起错误。因此,错误一定是在将FormArray注入为字符串时发生,虽然也可以将其作为字符串注入到FormArray的值中,但你并没有正确地执行。 code in github use path about

import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Observable } from 'rxjs';
import { TeamManagementService } from '../empleados/team-management.service';

@Component({
  selector: 'app-list-other-condition',
  templateUrl: './list-other-condition.component.html',
  styleUrls: ['./list-other-condition.component.css']
})
export class ListOtherConditionComponent implements OnInit {
  @Input()
  formGroup!:FormGroup
  
  @Input()
  employees!:  FormArray
  allSkills!: Observable<any[]>;
  constructor(private fbchild: FormBuilder,private teamMngService: TeamManagementService, private fb: FormBuilder, private readonly cdr: ChangeDetectorRef){
    this.allSkills = this.teamMngService.getSkills()
  }
  
  ngOnInit(): void {
    if (this.employees.length === 0)
    this.addEmployee();

  }
  get age() { return this.employees.get('age'); }

  get empName() { return this.employees.get('empName'); }
 
    addEmployee() {
        let fg = this.createEmpFormGroup();
        this.employees.push(fg);
    }
  deleteEmployee(idx: number) {
        this.employees.removeAt(idx);
    }
  
  public errorHandling = (control: string, error: string) => {
    return this.formGroup.controls[control].hasError(error);
  }

  createEmpFormGroup() {
        return this.fb.group({
            //empName: ['', [Validators.required]],
      empName:this.fbchild.control(null, Validators.required),
        //  age: ['', [Validators.required,Validators.min(21)]],
    age:this.fbchild.control(null, [Validators.required,Validators.min(21)]),
        //  skill: ['', [Validators.required]],
    skill:this.fbchild.control(null, Validators.required),
        })}

}

<!-- begin snippet: js hide: false console: true babel: false -->
<p>list-other-condition works!</p>
<form [formGroup]="formGroup">
    <div formArrayName="employees">
        <div *ngFor="let emp of employees.controls; let i = index" [formGroupName]="i" class="employee">
            
          <mat-label>Employee : {{i + 1}}</mat-label>
       
            <mat-label>Name :</mat-label> 
            <mat-form-field >
            <input matInput formControlName="empName">
            
          </mat-form-field>
          <mat-error *ngIf="employees.controls[i].get('empName')?.errors?.required">empName is required</mat-error>
            
            
            
          Age :
            <mat-form-field >
            <input matInput formControlName="age">
            
          </mat-form-field>
          <mat-error   *ngIf="employees.controls[i].get('age')?.errors?.required"> Age required.</mat-error>
          <mat-error *ngIf="employees.controls[i].get('age')?.errors?.min">
           
            Minimum age is 21.
        
</mat-error>


            
            
             
             
             
            
           

          <h2>Skill :</h2>
          <mat-form-field>
            <mat-label>Your skill</mat-label>
            <mat-select  formControlName="skill"required>
              <mat-option *ngFor="let skill of allSkills | async" [value]="skill.name" >
                {{ skill.displayName }}
              </mat-option>
            </mat-select>
            
            
            </mat-form-field>
            <mat-error
              *ngIf="employees.controls[i].get('skill')?.errors?.required"
             
              >You must make a selection </mat-error>
         <p>
            <button mat-flat-button color="primary" type="button" (click)="deleteEmployee(i)">Delete</button>
          </p> 
        
      </div>
      <button mat-flat-button color="primary" type="button" (click)="addEmployee()">Add More Employee</button>
    </div>
    </form>

<h3>Create New Team</h3>
<mat-card>
  <mat-card-header>
    <mat-card-title>Crear Team</mat-card-title>
  </mat-card-header>
  <mat-card-content>
    
  <form [formGroup]="teamForm" (ngSubmit)="onFormSubmit()">
    
   <h2>Team Name :</h2> 
      <mat-form-field >
      <input matInput formControlName="teamName">
     
      </mat-form-field>
    <mat-error>  
      <span *ngIf="!teamName?.valid && teamName?.touched">Please enter Team Name !!!</span>  
  </mat-error>  
    

  
    
    <h2>Employees in Team:</h2>
  
     
 
  
  
      <app-list-other-condition [formGroup]="teamForm" [employees]="employees" ></app-list-other-condition>
      <mat-card-actions>
      <button mat-flat-button color="primary" type="submit" [disabled]="!teamForm.valid">SUBMIT</button>
      </mat-card-actions>
  </form>
</mat-card-content>
  
</mat-card>
<p>Form Status: {{ teamForm.status }}</p>

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

import { TeamManagementService } from './team-management.service';
import { Team } from './team';
//import { Employee } from './employee';

@Component({
    selector: 'app-team',
    templateUrl: './team-management.component.html',
    styleUrls: ['./team-management.component.css']

})

export class TeamManagementComponent implements OnInit {
    teamForm = {} as FormGroup;
    //isValidFormSubmitted: boolean | null = null;
    allSkills: Observable<any[]>;
    constructor(
        private formBuilder: FormBuilder,
        private teamMngService: TeamManagementService) {
        this.allSkills = this.teamMngService.getSkills();
    }
    ngOnInit() {
        this.teamForm = this.formBuilder.group({
            teamName: ['', Validators.required],
            employees: this.formBuilder.array([])
                
        });
    }
    // teamForm.teamName.errors
    get formControls() { return this.teamForm.controls; }
    get teamName() {
        return this.teamForm.get('teamName');
    }
    get employees(): FormArray {
        return this.teamForm.get('employees') as FormArray;
    }
    //[disabled]="!teamForm.valid"
    onFormSubmit() {
        
    
    
        if (this.teamForm.valid) {
            console.log('form submitted');
          }
        let team: Team = this.teamForm.value;
        this.teamMngService.saveTeam(team);
        this.teamForm.reset();
    }
    resetTeamForm() {
        this.teamForm.reset();
    }
}

import { Injectable } from '@angular/core';
import { of } from 'rxjs';
import { Team } from './team';

const ALL_SKILLS = [
    { name: 'Java', displayName: 'Java' },
    { name: 'Angular', displayName: 'Angular' },
    { name: 'Dot Net', displayName: 'Dot Net' }
];

@Injectable({
    providedIn: 'root'
})
export class TeamManagementService {
    getSkills() {
        return of(ALL_SKILLS);
    }
    saveTeam(team: Team) {
        console.log('------------TEAM------------');
        console.log('Team Name: ' + team.teamName);
        console.log('----- Employee Details -----');
        for (let emp of team.employees) {
            console.log('Emp Name: ' + emp.empName);
            console.log('Emp age: ' + emp.age);
            console.log('Emp Skill: ' + emp.skill);
            console.log('-------------------');
        }
    }
}

   

你的问题可能是父组件与子组件之间的概念性错误导致的

在父组件和子组件之间的通信出现了问题。这可能是因为控件没有提供初始值且指定了必需验证器,而父组件的代码无法知道,或者还有以下原因:

FormArray 提供了一种收集动态创建的表单的方式,您可以使用索引和其中的控件访问每个表单。

<app-list-other-conditions [formGroup]="myform" [arrayName]="list">
and child

@Input()
arrayName!:  FormArray

尽管也可以将其作为字符串注入到FormArray值中,但它的访问方式与您定义的方式不同,因此应该正确处理。
@Input ()
arrayName !: string

我在员工文件夹中有一个使用草稿,位于文件team-management.component.ts中。 草稿 FormArray

错误 NG0100:在检查后表达式已更改。这是一种预防性机制,旨在防止模型数据和 UI 之间的不一致,以便不会向页面上的用户显示错误或旧数据。这可以捕获视图处于不一致状态的错误。例如,如果一个方法或 getter 每次被调用时返回不同的值,或者如果一个子组件更改其父级的值,则可能会出现这种情况。如果发生任何一种情况,这表明变更检测未稳定。Angular 抛出错误以确保始终正确反映数据在视图中,从而防止 UI 行为异常或可能无限循环。要确保不产生该错误,请在父组件中定义 FormArray,并将其作为 FormArray 发送到子组件中 error Expression Changed
像这个论坛中所示的那样,代码错误总是有可能出现 error required

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接