【问题标题】:How to troubleshoot ExpressionChangedAfterItHasBeenCheckedError: Previous value for 'ng-valid': 'true'. Current value: 'false'如何对 ExpressionChangedAfterItHasBeenCheckedError 进行故障排除:“ng-valid”的先前值:“true”。当前值:“假”
【发布时间】:2022-01-05 17:04:12
【问题描述】:

谁能帮我解决这个问题。当表单变为有效时会发生这种情况,但随后我返回并初始化此组件(在 FormArray 中推送一个新值(从零项))。如何确定触发了哪个属性 ng-valid?是数组吗?数组中的单个元素?还是整个表单组?

我尝试过ngAfterContentChecked() { this.cdr.detectChanges(); }changeDetection: ChangeDetectionStrategy.OnPush,并在推送调用后调用this.cdr.detectChanges()。还是不行。这很奇怪,因为它只在表单第一次有效时发生,然后我添加了一个 an 元素。

@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怎么样?类似于表单:FormGroup = this.fb.group ({ arrayName: this.fb.array ([]) }); y
  • 没错,它在父组件中<form [formGroup]="form" let myform = this.fb.group({ list: this.fb.array([]))}) 而这个子组件被称为<app-list-other-conditions [formGroup]="myform" arrayName="list"></...
  • 所以我不明白你为什么定义 arrayName !: string 因为它是一个数组,你可以上传父组件的代码和模板,所以我尝试执行它并查看你的问题。
  • 我定义了arrayName,因为它是模板构建所需要的(更容易使用formArrayName)。

标签: angular angular-material angular-reactive-forms


【解决方案1】:

我重复了您的代码的逻辑,在子项中启动了 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 中有一份使用草稿 draft FormArray

error NG0100: Expression has changed after it is checked 这是一个 建立警戒机制以防止两者之间的不一致 模型数据和 UI,以便错误或旧数据不会显示给 页面上的用户。这会捕获视图留在 不一致的状态。这可能发生,例如,如果一个方法或 getter 每次被调用时返回不同的值,或者如果一个孩子 组件更改其父级的值。如果出现上述任何一种情况,这 是变化检测不稳定的标志。角抛出 错误以确保数据始终正确反映在视图中,这 防止不稳定的 UI 行为或可能的无限循环。做 确保不会产生错误在父级中定义 FormArray 组件并将其作为 FormArray 发送到子组件 error Expression Changed

总是会出现代码错误,正如本答案中所示 论坛error required

【讨论】:

    猜你喜欢
    • 2019-05-22
    • 2016-04-15
    • 2023-03-31
    • 1970-01-01
    • 2011-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多