角度模板通信一个滴答延迟

时间:2018-03-28 11:04:49

标签: angular ng-template

我一直在玩ng-template,发现自己正在努力解决某些问题。

我在stackblitz中创建了一个简单的例子。 https://stackblitz.com/edit/angular-template-series-v?file=app%2Fparent%2Fparent1.component.ts

组件通过模板将 Hello 组件发送到组件。

这个想法是从中控制模板 儿童使用 ngIf

Hello 组件到达 ngOnInit 挂钩周期时,它会发出输出。父组件抓取此输出并添加要显示的消息。

但是创建组件时不会显示消息,而是在一个周期之后显示。在示例中,您需要单击两次按钮"切换内容"为了使消息"模板创建"出现。

如何解决这个问题,以使消息出现在同一个循环中?

3 个答案:

答案 0 :(得分:3)

这是由于角度变化检测的工作原理。它与使用ng-template无关,因为此modified stackblitz显示(使用不使用ng-template的大孩子)。

关于变化检测的2件事要知道:

  • 在事件(点击,提交,...),xhr请求或计时器之后触发。
  • 它从组件树的顶部到底部发生

基本上,当您点击切换按钮时:

  • 触发处理程序(在您的示例中切换showContent的值,但没有其他内容。hello组件在此阶段
  • 更改检测,始终从上到下开始。
  • angular开始于检查是否需要为父组件更新视图。由于尚未更改任何内容,因此父视图不会更新。
  • 子组件然后检测到其showContentValue已更改。这会导致创建hello组件。
  • 初始化hello组件后,会发出created事件。父组件收到此事件并相应地更新消息数组。但是此时已经检查了父母的内容,因此Angular不会修改父视图。

再次单击切换按钮时,会再次运行相同的循环,这次显示上一循环中数组中推送的消息

这是一个带有生命周期挂钩日志的modified stackblitz example

注意

强制更改检测再次运行将在此处解决您的问题,但如果您没有直接从子级到父级进行通信,则最好使用共享服务(基于observables)在不相关的组件之间广播消息

答案 1 :(得分:1)

如果您在父级中运行changeDetector,它将从第一次单击更新页面。

以下是一个示例:stackblitz

答案 2 :(得分:1)

这是因为你打破了Angular变化检测周期。

点击第一个切换按钮后,会发生以下情况:

1-您点击切换

2- ZoneJS,其中点击事件中的钩子会收到通知(简单地说)

3- Zone确保点击事件已完成

4- Zone将让Angular知道发生了async事件,我们必须检查组件并确保视图(DOM)反映模型(模型/ javascript世界)。因此change detection将运行,它将检测所有更改并发现模板中存在绑定(ng-if)。

5- ngIf变为真后,并注意,这是完全同步ng-container已创建,templateOutlet已创建,您的将呈现hello组件。

再次注意:这是全部同步。

6 - 视图已更新,更改检测现已解除。

7 - 在您的hello组件中,您可以触发另一个created事件并通知父组件,并在您的父组件内改变数组,并且Angular并不关心这一点,因为没有异步事件,也没有更新任何输入,你刚刚在更改检测完成工作后触发了另一个同步事件。

8-现在更新了数组,但视图不是(在父组件中)

9 - 再次单击,同样发生,Angular在第一次更改检测运行中更新父视图,并且您看到数组正在视图中反映。

证明我是对的:D:

 onTemplateCreated() {
    console.log('Got the event from chil');
   this.template.push('Template created');
    console.log('this.template',this.template);
  }

您会看到点击后,控制台显示正确的数组,但视图不会再次点击。

现在让我们转到我的代码

 onTemplateCreated() {
    console.log('Got the event from chil');
   this.template = [...this.template,'Template created'];
  }

因为我没有变异并且正在更新参考,Angular现在必须关心这个变化,但是还有一个问题,Angular的变化检测器已经完成并且您在没有运行的情况下更新了模型任何async事件,所以我们遇到麻烦,因为Angular不喜欢在更改检测完成后更新模型,

所以你会被抛出一个错误,上面写着:

  

ExpressionChangedAfterItHasBeenCheckedError:表达式在检查后发生了变化。以前的值

要解决这个问题,first read my other post to understand it,其次,您需要告诉Angular您知道自己在做什么并手动运行更改检测:

  this._cd.detectChanges

或者,您可以将其设为异步:

onTemplateCreated() {
    console.log('Got the event from chil');
   setTimeout(()=>{
      this.template = [...this.template,'Template created'];
   })
  }