Angular @ViewChild 未在路由器出口负载上加载
Angular @ViewChild not loading on Router Outlet load
我有下面的屏幕,其中有 4 个按钮,我正在使用它来完成有关在组件之间传递数据的教程 (Sharing Data Between Angular Components - Four Methods)。
我在使用@ViewChild 部分时遇到问题。四个按钮下方有一个路由器链接,每个按钮上都有一个路由器链接,单击相关组件。
当我单击 @ViewChild 按钮时,组件显示但消息未填充,它是空的。
当我第二次单击 @ViewChild 按钮时,消息按预期填充。
我确定这不是@ViewChild 的预期结果。所以我需要知道它为什么这样做以及如何更正它以便在第一次点击时显示该消息。
教程说:'we need to implement the AfterViewInit lifecycle hook to receive the data from the child' 我已经完成了。
下面是我的 Parent 和 Child 代码。
Parent
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from './child/child.component';
@Component({
selector: 'app-data-view-child',
templateUrl: './data-view-child.component.html',
styleUrls: ['./data-view-child.component.scss']
})
export class DataViewChildComponent implements AfterViewInit {
@ViewChild(ChildComponent, { static: false }) child;
constructor() { }
message: string;
ngAfterViewInit() {
this.message = this.child.message
}
}
Child
import { Component } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.scss']
})
export class ChildComponent {
message = 'Hola Mundo!';
constructor() { }
}
Parent模板
<div class="parent-card">
<h1>I am the Parent component</h1>
<h2 class="tac">Message: {{ message }}</h2>
<app-child></app-child>
</div>
请告诉我为什么第一次点击时消息不可用。
为此使用 activate
事件。
父组件:
<div class="container">
<router-outlet (activate)="onActivate($e)"></router-outlet>
</div>
onActivate(componentRef) {
componentRef.myFunc();
}
子组件:
myFunc() {
console.log("my function");
}
这里的问题是违反了单向数据流,导致更改检测无法正确触发。单向数据流意味着数据需要在变更检测期间向上或向下流动您的组件树。实例化组件树是数据向下流动,但是在实例化过程中试图从子树中拉出数据意味着你违反了将其拉回来的原则。 Angular 不允许这样做,因为它会创建一个无限的变化检测循环,其中父级触发子级,子级触发父级,依此类推。
如果你 运行 处于开发模式,你会看到类似 "expression changed after checked" 的错误......变化检测周期。
你可以像这样做很多骇人听闻的事情:
ngAfterViewInit() {
setTimeout(() => {
this.message = this.child.message;
});
}
这将解决您的问题,因为超时将触发父级中的另一轮更改检测。
但这里的问题是你不应该尝试这样做并且显示出糟糕的架构。数据应该响应事件到达父级,而不是实例化
演示闪电战:.https://stackblitz.com/edit/angular-zzc7r6?file=src/app/app.component.ts
我有下面的屏幕,其中有 4 个按钮,我正在使用它来完成有关在组件之间传递数据的教程 (Sharing Data Between Angular Components - Four Methods)。
我在使用@ViewChild 部分时遇到问题。四个按钮下方有一个路由器链接,每个按钮上都有一个路由器链接,单击相关组件。
当我单击 @ViewChild 按钮时,组件显示但消息未填充,它是空的。
当我第二次单击 @ViewChild 按钮时,消息按预期填充。
我确定这不是@ViewChild 的预期结果。所以我需要知道它为什么这样做以及如何更正它以便在第一次点击时显示该消息。
教程说:'we need to implement the AfterViewInit lifecycle hook to receive the data from the child' 我已经完成了。
下面是我的 Parent 和 Child 代码。
Parent
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from './child/child.component';
@Component({
selector: 'app-data-view-child',
templateUrl: './data-view-child.component.html',
styleUrls: ['./data-view-child.component.scss']
})
export class DataViewChildComponent implements AfterViewInit {
@ViewChild(ChildComponent, { static: false }) child;
constructor() { }
message: string;
ngAfterViewInit() {
this.message = this.child.message
}
}
Child
import { Component } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.scss']
})
export class ChildComponent {
message = 'Hola Mundo!';
constructor() { }
}
Parent模板
<div class="parent-card">
<h1>I am the Parent component</h1>
<h2 class="tac">Message: {{ message }}</h2>
<app-child></app-child>
</div>
请告诉我为什么第一次点击时消息不可用。
为此使用 activate
事件。
父组件:
<div class="container">
<router-outlet (activate)="onActivate($e)"></router-outlet>
</div>
onActivate(componentRef) {
componentRef.myFunc();
}
子组件:
myFunc() {
console.log("my function");
}
这里的问题是违反了单向数据流,导致更改检测无法正确触发。单向数据流意味着数据需要在变更检测期间向上或向下流动您的组件树。实例化组件树是数据向下流动,但是在实例化过程中试图从子树中拉出数据意味着你违反了将其拉回来的原则。 Angular 不允许这样做,因为它会创建一个无限的变化检测循环,其中父级触发子级,子级触发父级,依此类推。
如果你 运行 处于开发模式,你会看到类似 "expression changed after checked" 的错误......变化检测周期。
你可以像这样做很多骇人听闻的事情:
ngAfterViewInit() {
setTimeout(() => {
this.message = this.child.message;
});
}
这将解决您的问题,因为超时将触发父级中的另一轮更改检测。
但这里的问题是你不应该尝试这样做并且显示出糟糕的架构。数据应该响应事件到达父级,而不是实例化
演示闪电战:.https://stackblitz.com/edit/angular-zzc7r6?file=src/app/app.component.ts