草庐IT

javascript - 动态嵌套 react 形式 : ExpressionChangedAfterItHasBeenCheckedError

coder 2024-05-11 原文

我的 react 形式是三个组件级别深。父组件创建一个没有任何字段的新表单并将其传递给子组件。

首先,外部形式是有效的。稍后,子组件会添加带有验证器(失败)的新表单元素,从而使外部表单无效。

我在控制台中收到一个ExpressionChangedAfterItHasBeenCheckedError 错误。我想修复该错误。

不知何故,这只会在我添加第三层嵌套时发生。同样的方法似乎适用于两层嵌套。

笨蛋: https://plnkr.co/edit/GymI5CqSACFEvhhz55l1?p=preview

父组件

@Component({
  selector: 'app-root',
  template: `
    myForm.valid: <b>{{myForm.valid}}</b>
    <form>
      <app-subform [myForm]="myForm"></app-subform>
    </form>
  `
})
export class AppComponent implements OnInit {
  ...

  ngOnInit() {
    this.myForm = this.formBuilder.group({});
  }
}

子组件

@Component({
  selector: 'app-subform',
  template: `
    <app-address-form *ngFor="let addressData of addressesData;"
      [addressesForm]="addressesForm">
    </app-address-form>
  `
})
export class SubformComponent implements OnInit {
  ...

  addressesData = [...];

  constructor() { }

  ngOnInit() {
    this.addressesForm = new FormArray([]);
    this.myForm.addControl('addresses', this.addressesForm);
  }

子组件

@Component({
  selector: 'app-address-form',
  template: `
    <input [formControl]="addressForm.controls.addressLine1">
    <input [formControl]="addressForm.controls.city">
  `
})
export class AddressFormComponent implements OnInit {
  ...

  ngOnInit() {
    this.addressForm = this.formBuilder.group({
      addressLine1: [
        this.addressData.addressLine1,
        [ Validators.required ]
      ],
      city: [
        this.addressData.city
      ]
    });

    this.addressesForm.push(this.addressForm);
  }
}

最佳答案

要了解您需要阅读的问题 Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error文章。

对于您的特定情况,问题是您在 AppComponent 中创建表单并在 DOM 中使用 {{myForm.valid}} 插值。这意味着 Angular will run create and run updateRenderer function对于更新 DOM 的 AppComponent。然后使用子组件的 ngOnInit 生命周期 Hook 将具有控件的子组添加到此表单:

export class AddressFormComponent implements OnInit {
  @Input() addressesForm;
  @Input() addressData;

  ngOnInit() {
    this.addressForm = this.formBuilder.group({
      addressLine1: [
        this.addressData.addressLine1,
        [ Validators.required ]   <-----------
      ]

    this.addressesForm.push(this.addressForm); <--------

控件变得无效,因为您没有提供初始值并且指定了所需的验证器。因此整个表单变得无效,表达式 {{myForm.valid}} 的计算结果为 false。但是,当 Angular 为 AppComponent 运行更改检测时,它评估为 true。这就是错误所说的。

一个可能的修复方法是在开始时将表单标记为无效,因为您打算添加必需的验证器,但 Angular 似乎没有提供这种方法。您最好的选择可能是异步添加控件。事实上,这就是 Angular 在源代码中所做的:

const resolvedPromise = Promise.resolve(null);

export class NgForm extends ControlContainer implements Form {
  ...

  addControl(dir: NgModel): void {
    // adds controls asynchronously using Promise
    resolvedPromise.then(() => {
      const container = this._findContainer(dir.path);
      dir._control = <FormControl>container.registerControl(dir.name, dir.control);
      setUpControl(dir.control, dir);
      dir.control.updateValueAndValidity({emitEvent: false});
    });
  }

所以对于你来说,它将是:

const resolvedPromise = Promise.resolve(null);

@Component({
   ...
export class AddressFormComponent implements OnInit {
  @Input() addressesForm;
  @Input() addressData;

  addressForm;

  ngOnInit() {
    this.addressForm = this.formBuilder.group({
      addressLine1: [
        this.addressData.addressLine1,
        [ Validators.required ]
      ],
      city: [
        this.addressData.city
      ]
    });

    resolvedPromise.then(() => {
       this.addressesForm.push(this.addressForm); <-------
    })
  }
}

或者在 AppComponent 中使用一些变量来保存表单状态并在模板中使用它:

{{formIsValid}}

export class AppComponent implements OnInit {
  myForm: FormGroup;
  formIsValid = false;

  constructor(private formBuilder: FormBuilder) {}

  ngOnInit() {
    this.myForm = this.formBuilder.group({});
    this.myForm.statusChanges((status)=>{
       formIsValid = status;
    })
  }
}

关于javascript - 动态嵌套 react 形式 : ExpressionChangedAfterItHasBeenCheckedError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45661010/

有关javascript - 动态嵌套 react 形式 : ExpressionChangedAfterItHasBeenCheckedError的更多相关文章

  1. ruby-on-rails - Rails 编辑表单不显示嵌套项 - 2

    我得到了一个包含嵌套链接的表单。编辑时链接字段为空的问题。这是我的表格:Editingkategori{:action=>'update',:id=>@konkurrancer.id})do|f|%>'Trackingurl',:style=>'width:500;'%>'Editkonkurrence'%>|我的konkurrencer模型:has_one:link我的链接模型:classLink我的konkurrancer编辑操作:defedit@konkurrancer=Konkurrancer.find(params[:id])@konkurrancer.link_attrib

  2. ruby - 将散列转换为嵌套散列 - 2

    这道题是thisquestion的逆题.给定一个散列,每个键都有一个数组,例如{[:a,:b,:c]=>1,[:a,:b,:d]=>2,[:a,:e]=>3,[:f]=>4,}将其转换为嵌套哈希的最佳方法是什么{:a=>{:b=>{:c=>1,:d=>2},:e=>3,},:f=>4,} 最佳答案 这是一个迭代的解决方案,递归的解决方案留给读者作为练习:defconvert(h={})ret={}h.eachdo|k,v|node=retk[0..-2].each{|x|node[x]||={};node=node[x]}node[

  3. Ruby——嵌套类和子类是一回事吗? - 2

    下面例子中的Nested和Child有什么区别?是否只是同一事物的不同语法?classParentclassNested...endendclassChild 最佳答案 不,它们是不同的。嵌套:Computer之外的“Processor”类只能作为Computer::Processor访问。嵌套为内部类(namespace)提供上下文。对于ruby​​解释器Computer和Computer::Processor只是两个独立的类。classComputerclassProcessor#Tocreateanobjectforthisc

  4. ruby - 模块嵌套代码风格偏好 - 2

    我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的

  5. ruby-on-rails - 使用回形针的嵌套形式 - 2

    我有一个名为posts的模型,它有很多附件。附件模型使用回形针。我制作了一个用于创建附件的独立模型,效果很好,这是此处说明的View(https://github.com/thoughtbot/paperclip):@attachment,:html=>{:multipart=>true}do|form|%>posts中的嵌套表单如下所示:prohibitedthispostfrombeingsaved:@attachment,:html=>{:multipart=>true}do|at_form|%>附件记录已创建,但它是空的。文件未上传。同时,帖子已成功创建...有什么想法吗?

  6. ruby-on-rails - Rails 3,嵌套资源,没有路由匹配 [PUT] - 2

    我真的为这个而疯狂。我一直在搜索答案并尝试我找到的所有内容,包括相关问题和stackoverflow上的答案,但仍然无法正常工作。我正在使用嵌套资源,但无法使表单正常工作。我总是遇到错误,例如没有路线匹配[PUT]"/galleries/1/photos"表格在这里:/galleries/1/photos/1/edit路线.rbresources:galleriesdoresources:photosendresources:galleriesresources:photos照片Controller.rbdefnew@gallery=Gallery.find(params[:galle

  7. ruby - 如何根据长度将路径数组转换为嵌套数组或散列 - 2

    我需要根据字符串路径的长度将字符串路径数组转换为符号、哈希和数组的数组给定以下数组:array=["info","services","about/company","about/history/part1","about/history/part2"]我想生成以下输出,对不同级别进行分组,根据级别的结构混合使用符号和对象。产生以下输出:[:info,:services,about:[:company,history:[:part1,:part2]]]#altsyntax[:info,:services,{:about=>[:company,{:history=>[:part1,:pa

  8. ruby - 在 Ruby 中动态创建数组 - 2

    有没有办法在Ruby中动态创建数组?例如,假设我想遍历用户输入的书籍数组:books=gets.chomp用户输入:"TheGreatGatsby,CrimeandPunishment,Dracula,Fahrenheit451,PrideandPrejudice,SenseandSensibility,Slaughterhouse-Five,TheAdventuresofHuckleberryFinn"我把它变成一个数组:books_array=books.split(",")现在,对于用户输入的每一本书,我想用Ruby创建一个数组。伪代码来做到这一点:x=0books_array.

  9. ruby - 是否可以将 IRB 提示配置为动态更改? - 2

    我想在IRB中浏览文件系统并让提示更改以反射(reflect)当前工作目录,但我不知道如何在每个命令后进行提示更新。最终,我想在日常工作中更多地使用IRB,让bash溜走。我在我的.irbrc中试过这个:require'fileutils'includeFileUtilsIRB.conf[:PROMPT][:CUSTOM]={:PROMPT_N=>"\e[1m:\e[m",:PROMPT_I=>"\e[1m#{pwd}>\e[m",:PROMPT_S=>"FOO",:PROMPT_C=>"\e[1m#{pwd}>\e[m",:RETURN=>""}IRB.conf[:PROMPT_MO

  10. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

随机推荐