如何在 Angular 2 上实现 ngOnChanges 以进行输入验证,而不触发“检查后表达式已更改。”错误

Posted

技术标签:

【中文标题】如何在 Angular 2 上实现 ngOnChanges 以进行输入验证,而不触发“检查后表达式已更改。”错误【英文标题】:How to implement ngOnChanges for input validation on angular 2 without triggering ' Expression has changed after it was checked.' error 【发布时间】:2017-06-14 18:24:04 【问题描述】:

我尝试编写自己的自定义组件,该组件使用正则表达式进行基本验证,可以作为组件的输入。有两种情况,一种是表单最初为空(新项目表单),另一种是数据已经存在(编辑)。

问题是,当我在最初设置数据后尝试验证字段时,通常会得到“检查后表达式已更改。”。我明白为什么要进行这项检查以及为什么会发生错误,但我不明白这是什么意思 'ngOnChanges' 如果我不能从中更改组件状态?在这种情况下,状态变化是 'isValid' 布尔标志,它会导致组件边框变为红色。

我尝试了以下方法:

this.changeDetect.detectChanges(),在 ngOnChanges 之前和之后。 将“文本”更改为 getter/setter 对。将验证日志移到那里。同样的错误。我认为这是 与 ngOnChanges 基本相同,所以没有任何意外。 ngAfterViewInit 不验证代码更新表单的情况(对于 例如,来自后端的查询 -> 已填写编辑表单。)错误 但是不会发生。 将 changeDetection 策略设置为在 @Component 装饰器处推送。 超时...没有变化,如果我设置超时超过 1 秒,则没有任何反应,如果 更少的错误发生。这可能与开发模式检查有关 这似乎发生在初始更改检测后 1 秒。

这感觉非常常见和简单的用例,因此我想我在这里错过了一些非常简单的东西。

示例用法:

<cx-form-text-input validate=".+" label="Rekisterinumero*" [(text)]="ticket.registerPlate" format="uppercase"></cx-form-text-input>

示例组件:

@Component(
  selector: 'cx-form-text-input',
  templateUrl: './form-text-input.component.html',
  styleUrls: ['./form-text-input.component.scss']
)
export class FormTextInputComponent implements OnChanges 
  @Input()
  public text: string;

  @Output() textChange = new EventEmitter();

  @Input() public validate;

  @Input() public label: string = 'DEFAULT LABEL';

  @Input() public disabled = false;

  @Input() format: string;

  public entry: FormEntry;

  constructor(private form: FormContext, private changeDetect: ChangeDetectorRef) 
    this.entry = form.Join();
  

  private applyFormat(text: string): string 
    switch (this.format) 
      case 'uppercase':
        return text.toUpperCase();
      default:
        return text;
    
  

  public isDisabled(): boolean 
    return this.disabled || this.form.disabled;
  

  public keyboardEvent() 
    this.entry.isDirty = true;
    this.text = this.applyFormat(this.text);
    this.validateData();

    this.textChange.emit(this.text);
  

  private validateData() 
    if (!this.validate) 
      this.entry.isValid = true;
      return;
    

    if (!this.text) 
      this.entry.isValid = false;
      return;
    

    this.entry.isValid = !!this.text.match(this.validate);
  

  ngOnChanges(changes: SimpleChanges) 
    this.validateData(); // The painpoint...
  

错误:

EXCEPTION: Error in ./EditFormComponent class EditFormComponent - inline template:6:72 caused by: Expression has changed after it was checked. Previous value: 'true'. Current value: 'false'.
ORIGINAL EXCEPTION: Expression has changed after it was checked. Previous value: 'true'. Current value: 'false'.
ORIGINAL STACKTRACE:

【问题讨论】:

【参考方案1】:
 ngOnChanges(changes: SimpleChanges) 
    this.validateData(); // The painpoint...
    this.changeDetect.detectChanges(); // <<<=== invoke change detection at the end of `ngOnChanges` if the model was modified 
  

【讨论】:

已经试过了,i.imgur.com/PnVsfpt.png,没有帮助。那么这应该有效吗?如果是这样,我认为我的代码中可能还有其他原因导致它。或者这是角度 2 中的错误。但是我从 2.1 -> 2.4 开始使用,但仍然会发生这种情况。 错误信息是关于EditFormComponent 并且您问题中的代码显示FormTextInputComponent。我的答案仅在更改仅影响当前类的模型(FormTextInputComponent)时才有效。您可以尝试注入private appRef: ApplicationRef 并调用this.appRef.tick() 嗯,是的,这很好!明天我会检查一下,如果我可以追踪链回到 EditFormComponent 并找出验证后导致错误的原因。

以上是关于如何在 Angular 2 上实现 ngOnChanges 以进行输入验证,而不触发“检查后表达式已更改。”错误的主要内容,如果未能解决你的问题,请参考以下文章

Angular 针对 Asp.Net WebApi,在服务器上实现 CSRF

如何在 2 个视图控制器上实现广告

如何在 UIImageView 上实现点击并按住?

如何使用 ngModel 在 div 的 innerhtml 属性上实现 2 路数据绑定?

在python中,我应该如何在元组列表上实现最小堆?

如何在android Firestore上实现Paginate查询[重复]