【问题标题】:Problems in communication between parent and child - Angular 6父母和孩子之间的沟通问题 - Angular 6
【发布时间】:2020-01-29 20:13:47
【问题描述】:

我正在尝试根据子输出对父组件进行操作,但我得到了

表达式在检查后发生了变化。以前的值:'ngIf: [对象对象]'。当前值:'ngIf: true'。

这是我的代码:

父组件html

<div *ngIf="hasErrors">!</div>
<app-error [valuesForErrors]="..." (hasErrors)="setHasErrors($event)"></app-error>

父组件ts(节)

export class InputComponent implements OnInit {
    hasErrors = false;
    ...
    setHasErrors(hasErrors) {
        this.hasErrors = hasErrors;
    }

我从 rxjs 看到了一些带有 Subject 和 Observable 的解决方案,但它们在我的项目中不起作用:/

编辑

一位朋友帮我提供了另一个解决方案,只需在声明中使用 true 使发射器异步:

子组件 ts

export class ErrorComponent implements OnInit, OnChanges {
    @Input() valuesForErrors: any;
    @Output() hasErrors: EventEmitter<boolean> = new EventEmitter<boolean>(true);
    ...
    ngOnChanges(changes: SimpleChanges): void {
        this.calculateErrors()
    }

    calculateErrors() {
        let errors = ... some logic that returns a boolean;
        this.hasErrors.emit(errors);
    }
}

【问题讨论】:

  • 您从子函数 calculateErrors 发出的“错误”的值是多少?
  • 一个基于 valuesForErrors 计算的布尔值
  • 您在这里使用的方法——子组件计算状态(hasErrors)然后将其传播到父组件——似乎违反了“单向数据流”原则。如果将错误计算移到使用它的组件层次结构的最高点(即ParentComponent),然后让父级将其作为输入绑定提供给子级,从长远来看,它可能会简化事情。这也可能会修复错误。
  • 有时它与template hierarchy 有关 - 如果是这种情况,请将&lt;div *ngIf="hasErrors"&gt;!&lt;/div&gt; 包装在&lt;div *ngIf="true"&gt;!&lt;/div&gt;
  • @AndrewAllen 你是个疯子,这就像一个魅力,我仍然不明白为什么......非常感谢。请把它作为一个答案。

标签: angular rxjs


【解决方案1】:

你有没有想过这个世界是否只是为了得到你?

嗯,有时确实如此。您遇到了 angular 引发的最讨厌的行为之一。

通常,在 95% 的情况下,ExpressionChangedAfterItHasBeenCheckedError 基本上是有角度地告诉您您不了解生命周期检测的基础知识:ngOnChanges vs ngOnInit vs ngAfterViewInit。但有时这是因为嵌套和模板层次结构以及在您的模板中进行的顺序检查。

采取以下引发错误的方法:

<form [name]="formName"
      [formGroup]="formGroup">
  <div *ngIf="true">
    <input formControlName="name"
           required
           placeholder="Please enter you name">
  </div>
</form>
<div *ngIf="formGroup.valid">
  Name is required.
</div>

引发错误的原因是更改检测先评估错误 div 的 *ngIf,然后再评估输入的有效性,因为输入在模板层次结构方面低一级。

一种解决方法是通过在其周围添加另一个&lt;div *ngIf="true"&gt;&lt;/div&gt;(如上所述),将错误 div 置于与输入相同的级别。

Not all heros wear capes, some leave Github comments

【讨论】:

  • 我尝试做同样的事情,但是在使用
    的 html 代码中并没有工作。你知道为什么吗?
  • @DanielQuicazán 我已经用这个更新了 stackblitz...我需要考虑一下,然后再回复你。
  • 好的,但是,在我的代码中,验证是由子组件进行的。我已经实现了第一个解决方案,添加了一个 而不是 div,但是您提出的另一个解决方案听起来很有趣
  • @DanielQuicazán 我已经撤消了我的更新 - 没有可靠的方式来使用 pageLoaded,除非您确定 formGroup.valid 将在初始化时做什么
【解决方案2】:

像这样修改父组件:

import { ChangeDetectorRef } from '@angular/core';

constructor(private cd: ChangeDetectorRef) {  }


setHasErrors(hasErrors) {
    this.hasErrors = hasErrors;
    this.cd.detectChanges();
}

【讨论】:

  • 我找到了那个解决方案,但他们告诉我你不应该改变 Angular 生命周期。
  • 那么我们必须找出是什么导致了这个问题,如果你在stackbiltz中分享你的代码会很有帮助
  • 我发现这是由于 Angular 渲染组件的顺序造成的,所以,当您更改父组件中 hasErrors 的值时,它已经计算出是否必须渲染 div
猜你喜欢
  • 2011-02-20
  • 2019-02-04
  • 2011-02-21
  • 2017-07-01
  • 2019-05-22
  • 2021-04-25
  • 1970-01-01
  • 2020-04-21
  • 1970-01-01
相关资源
最近更新 更多