如何在离子4中使用离子输入修复* ngFor的ExpressionChangedAfterItHasBeenCheckedError

时间:2019-12-25 08:19:34

标签: angular ionic-framework ionic4

我目前有一个正通过* ngFor的离子输入,因此它会重复多次。当我想向* ngFor循环添加新记录(以添加新的离子输入行)时,出现以下错误:

ExpressionChangedAfterItHasBeenCheckedError:检查表达式后,表达式已更改。先前的值:'model:abc'。当前值:“型号:”。

这是我的代码:

.html

<ion-item *ngFor="let item of values; let i = index;">
      <ion-input formControlName="taskDetail" [(ngModel)] = "values[i].answer" type="text"></ion-input>
      <ion-icon name="remove-circle" (click)="removeTaskOption(i)" slot="end"></ion-icon>
</ion-item>

.ts

checklistCounter = [];
values = [];

constructor() {
    this.checklistCounter = Array(this.numCounter).fill(1).map((x, i) => i + 1);
    for (let i = 0; i < this.checklistCounter.length; i++) {
      let data = {
        id: i,
        answer:''
      }
      this.values.push(data);
    }
}


addNewTaskOption(){
  let data = {
    id: (this.values[this.values.length - 1].id + 1),
    answer:''
  }
 this.values.push(data);
}

removeTaskOption(i:number){
  this.values.splice(i, 1);
}

以下是一些图片供您参考:

原始UI的图像(在单击添加或删除离子输入行之前):

Image of Original UI (Before clicking on add or remove ion-input rows)

UI的图像(在第一个离子输入中输入“ abc”后,单击添加按钮:

Image of UI (After typing in 'abc' into the first ion-input then click on the add button)

错误图片:

enter image description here

即使用户在离子输入字段中输入了某些内容,我仍想实现的目标是,如果他们想添加更多字段,这些字段将仅显示在原始字段下方。我已经阅读了其他解决方案,但是所有这些解决方案都订阅了一项服务,而这些解决方案都是针对该解决方案的,因此我认为我无法将其应用于我的案例。请帮忙!

更新:通过遵循@GaurangDhorda的回答设法解决了该问题。

代码:

.html

<ion-item *ngFor="let item of values; let i = index;">
      <ion-input formControlName="taskDetail" [value]="item.answer" (change)="setQuantity($event.target.value, i)" type="text"></ion-input>
      <ion-icon name="remove-circle" (click)="removeTaskOption(i)" slot="end"></ion-icon>
</ion-item>

.ts(在新方法中添加)

setQuantity(ev:string, i:number){
     this.values[i].answer = ev;    
   }

3 个答案:

答案 0 :(得分:1)

其他警告: 被检查为“正确”的答案只是一种错误解决方法,该方法最初是将模板驱动的表单(ngModel)与反应形式混合在一起。 (formControlName)不应将其视为解决方案。

1)您可以使用模板驱动形式或反应驱动形式。混合它们并不能提供真实的价值,可以将其视为“代码异味”,并会导致错误(如您所见)。 当您想进行双向绑定时,建议您像在问题初稿中一样使用[(ngModel)]。但是然后请删除formControlName=taskDetail。 (无论如何,在taskDetail中使用相同的formControlName *ngFor是错误的)

2)现在有了解决方案,您基本上可以自己手动进行双向绑定。

3)我有两个示例显示您对template driven formsreactive forms的问题:

模板驱动 使用name

时,我们需要在您的input上拥有一个独特的ngModel属性
    <form>
      <ion-item *ngFor="let item of values; let i = index;">
        <ion-input [(ngModel)]="item.answer" type="text" name="answer_{{i}}"></ion-input>
        <button (click)="removeTaskOption(i)">Remove</button>
      </ion-item>

      <button (click)="addNewTaskOption()">Add answer</button>
    </form>

活动表格 反应形式带有更多要在组件类中编写的形式。在那里,我们设置了一个FormArray来保存值:

    <form [formGroup]="myForm">

      <div formArrayName="taskDetail">
        <ion-item *ngFor="let item of taskDetail.controls; let i = index;">
          <ion-input [formControlName]="i" type="text"></ion-input>
          <button (click)="removeTaskOption(i)">Remove</button>
        </ion-item>
      </div>

      <button (click)="addNewTaskOption()">Add answer</button>

    </form>
export class AppComponent {

  myForm = new FormGroup({
    taskDetail: new FormArray([
      new FormControl('value 1'),
      new FormControl('value 2')
    ])
  });

  get taskDetail() {
    return this.myForm.get('taskDetail') as FormArray;
  }

  addNewTaskOption(){
    this.taskDetail.push(new FormControl('value NEWWW'));
  }

  removeTaskOption(i:number){
    this.taskDetail.removeAt(i);
  }
  ...
}

答案 1 :(得分:0)

import socket
socket_args = {'family': socket.AF_INET, 'type': socket.SOCK_STREAM, 'proto': 0}
# ...

# pickle socket_args here
# ...

# load socket_args
socket_object = socket.socket(**socket_args)

答案 2 :(得分:-1)

在生产模式下不会出现以下错误。

在ngAfterViewInit()生命周期模式下添加值代码。