简体   繁体   English

Angular 6 @Viewchild不支持延迟加载

[英]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 每当实例化新组件时,路由器插座将发出激活事件

Angular Docs Angular Docs

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. 你将只能得到ChildComponentParentComponent 只有当你有<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将加载到您的ParentComponentrouter-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获取ParentComponentChildComponent属性,您必须使用SharedService或者您必须将路径中的ChildProperty作为QueryParam传递,并使用ActivatedRoute在ParentComponent中读取它

UPDATE: 更新:

Sharing Data using Route Query Params: 使用Route Query Params共享数据:

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']);
    });
    ...
  }

  ...

}

Using a 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 : 然后,您可以在ParentComponentChildComponent注入它:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM