[英]Angular 6 @Viewchild is not working with lazy loading
Here is my code that gives error cannot read property title undefined. 这是我的代码,给出错误无法读取属性标题undefined。
Parent Component 父组件
import { Child } from './child.component';
@Component({
selector: 'parent',
})
export class ParentComponet implements OnInit, AfterViewInit {
constructor(){}
@ViewChild(Child) child: Child;
ngAfterViewInit(){
console.log("check data", this.child.title)
}
}
And Child Component is. 和儿童组件是。
@Component({
selector: 'child',
})
export class ChildComponet {
public title = "hi"
constructor(){}
}
routing.module.ts is like routing.module.ts就像
{
path: "",
component: ParentComponent,
children: [
{
path: '/child',
component: ChildComponent
}
]
}
And Gives error is 并且给出了错误
ERROR TypeError: Cannot read property 'title' of undefined(…)
I think you are missing 'template' or 'templateUrl' in relevance to creating a Component 我认为你缺少与创建组件相关的'template'或'templateUrl'
ParentComponent 为父级
import { ChildComponent } from './child.component'; // {ChildComponent} not {Child} as we are referencing it to the exported class of ChildComponent
@Component({
selector: 'parent',
template: `<child></child>`
})
export class ParentComponet implements OnInit, AfterViewInit {...}
ChildComponent ChildComponent
@Component({
selector: 'child',
template: `<h1>{{ title }}</h1>`
})
export class ChildComponent {...} // Be sure to spell it right as yours were ChildComponet - missing 'n'
UPDATE as per the user's clarification on this thread 根据用户对此主题的说明进行更新
Had added a Stackblitz Demo for your reference (Check the console) 已添加Stackblitz演示供您参考(检查控制台)
If you want to access the ChildComponent that is rendered under the Parent Component's <router-outlet>
you can do so by utilizing (activate) supported property of router-outlet : 如果要访问在父组件的<router-outlet>
下呈现的ChildComponent,可以通过利用(激活)router-outlet支持的属性来实现 :
A router outlet will emit an activate event any time a new component is being instantiated 每当实例化新组件时,路由器插座将发出激活事件
ParentComponent's Template ParentComponent的模板
@Component({
selector: 'parent',
template: `<router-outlet (activate)="onActivate($event)"></router-outlet>`
})
export class ParentComponent {
onActivate(event): void {
console.log(event); // Sample Output when you visit ChildComponent url
// ChildComponent {title: "hi"}
console.log(event.title); // 'hi'
}
}
The result will differ based on the visited page under your parent's children 结果将根据父母子女下的访问页面而有所不同
If you visit Child1Component you will get its instance
Child1Component {title: "hi"}
如果您访问Child1Component,您将获得其实例Child1Component {title: "hi"}
If you visit Child2Component you will get its instance
Child2Component {name: "Angular"}
如果您访问Child2Component,您将获得其实例Child2Component {name: "Angular"}
These results will then be reflected on your ParentComponent's onActivate(event) console for you to access 然后,这些结果将反映在ParentComponent的onActivate(事件)控制台上,供您访问
That's not how it's supposed to work. 这不是它应该如何工作。 You'll be only able to get the ChildComponent
in your ParentComponent
ONLY if you have the <app-child></app-child>
tag in your ParentComponent
Template. 你将只能得到ChildComponent
你ParentComponent
只有当你有<app-child></app-child>
标签在你ParentComponent
模板。
Something like this: 像这样的东西:
...
<app-child></app-child>
...
But since you're using child routing, and the ChildComponent
will load on the router-outlet
of your ParentComponent
you won't have access to that using ViewChild
但是,由于您正在使用子路由,并且ChildComponent
将加载到您的ParentComponent
的router-outlet
,您将无法使用ViewChild
访问它
PS: You'll only have access to it inside ngAfterViewInit
as ViewChild
can only be considered safe to have instantiated after the View has loaded: PS:你只能在ngAfterViewInit
访问它,因为ViewChild
在加载View之后只能被认为是安全的实例化:
import { Component, OnInit, ViewChild } from '@angular/core';
import { ChildComponent } from '../child/child.component';
...
@Component({...})
export class ParentComponent implements OnInit {
@ViewChild(ChildComponent) childComponent: ChildComponent;
...
ngAfterViewInit() {
console.log(this.childComponent);
}
}
Here's a Working Sample StackBlitz for your ref that illustrates your scenario in both the cases. 这是您的参考文献的工作示例StackBlitz ,它说明了两种情况下的情景。
PS: To get the ChildComponent
properties in your ParentComponent
, with Routing, you'll have to either use a SharedService
or you'll have to pass the ChildProperty in the route as a QueryParam and read it in your ParentComponent using the ActivatedRoute
PS:要使用Routing获取ParentComponent
的ChildComponent
属性,您必须使用SharedService
或者您必须将路径中的ChildProperty作为QueryParam传递,并使用ActivatedRoute
在ParentComponent中读取它
Although this won't make much sense, but in your ChildComponent
, you can have a Link that would route the user to the ChildComponent with the title
property passed as a queryParam
. 虽然这没有多大意义,但是在您的ChildComponent
,您可以拥有一个Link,它将用户路由到具有titleParam传递的title
属性的queryParam
。 Something like this: 像这样的东西:
<a
[routerLink]="['/child']"
[queryParams]="{title: title}">
Go To Child Route With Query Params
</a>
And in your ParentComponent
have access to it using ActivatedRoute
like this: 在您的ParentComponent
中可以使用ActivatedRoute
访问它,如下所示:
...
import { ActivatedRoute } from '@angular/router';
...
@Component({...})
export class ParentComponent implements OnInit {
...
constructor(
private route: ActivatedRoute,
...
) { }
ngOnInit() {
this.route.queryParams.subscribe(queryParams => {
console.log('queryParams[`title`]', queryParams['title']);
});
...
}
...
}
SharedService
使用SharedService
Just create a SharedService
with a private
BehaviorSubject
that would be exposed as an Observable
by calling the asObservable
method on it. 只需SharedService
private
BehaviorSubject
创建一个SharedService
,通过在其上调用asObservable
方法将其作为Observable
公开。 It's value can be set by exposing a method( setChildProperty
) that will essentially call the next
method with the updated childProperty
value : 可以通过公开一个方法( setChildProperty
)来设置它的值,该方法本质上会使用更新的childProperty
值调用next
方法:
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
@Injectable()
export class SharedService {
private childProperty: BehaviorSubject<string> = new BehaviorSubject<string>(null);
childProperty$: Observable<string> = this.childProperty.asObservable();
constructor() { }
setChildProperty(childProperty) {
this.childProperty.next(childProperty);
}
}
You can then inject it both in your ParentComponent
and in your ChildComponent
: 然后,您可以在ParentComponent
和ChildComponent
注入它:
In ChildComponent
set the value: 在ChildComponent
设置值:
import { Component, OnInit } from '@angular/core';
import { SharedService } from '../shared.service';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
public title = "hi"
constructor(private sharedService: SharedService) { }
ngOnInit() {
this.sharedService.setChildProperty(this.title);
}
}
And in your ParentComponent
get the value: 在您的ParentComponent
获取值:
...
import { SharedService } from '../shared.service';
@Component({...})
export class ParentComponent implements OnInit {
...
constructor(
...,
private sharedService: SharedService
) { }
ngOnInit() {
...
this.sharedService.childProperty$.subscribe(
childProperty => console.log('Got the Child Property from the Shared Service as: ', childProperty)
);
}
...
}
确保在parent.component.html
模板中添加了<child></child>
标记。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.