Angular 6 @Viewchild не работает с отложенной загрузкой - PullRequest
0 голосов
/ 05 декабря 2018

Вот мой код, который выдает ошибку, не может прочитать заголовок свойства undefined.

Родительский компонент

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)
  }
}

И дочерний компонент is.

@Component({
      selector: 'child',
    })
    export class ChildComponet {

     public title = "hi"
     constructor(){}

    }

routing.module.ts похож на

{
        path: "",
        component: ParentComponent,
        children: [
            {
                path: '/child',
                component: ChildComponent
            }
        ]
}

и дает ошибку

ERROR TypeError: Cannot read property 'title' of undefined(…)

Ответы [ 3 ]

0 голосов
/ 05 декабря 2018

Это не так, как это должно работать.Вы сможете получить ChildComponent в своем ParentComponent ТОЛЬКО , только если у вас есть <app-child></app-child> тег в вашем ParentComponent шаблоне.

Примерно так:

...

<app-child></app-child>

...

Но поскольку вы используете дочернюю маршрутизацию, и ChildComponent загрузит router-outlet вашего ParentComponent, у вас не будет доступа к нему с помощью ViewChild

PS: Доступ к нему будет возможен только внутри ngAfterViewInit, поскольку ViewChild можно считать безопасным для создания экземпляра только после загрузки представления:

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);
  }

}

Вот рабочий образец StackBlitz для вашего рефери, который иллюстрирует ваш сценарий в обоих случаях.

PS: Чтобы получить ChildComponent Свойства в вашем ParentComponent, в Routing вам придется либо использовать SharedService, либо вам нужно будет передать ChildProperty в маршрут как QueryParam и прочитать его в вашем ParentComponent, используя ActivatedRoute

ОБНОВЛЕНИЕ:

Обмен данными с использованием параметров запроса маршрута:

Хотя это не имеет особого смысла, но в вашем ChildComponent,у вас может быть ссылка, которая направит пользователя к ChildComponent со свойством title, переданным как queryParam.Примерно так:

<a 
  [routerLink]="['/child']" 
  [queryParams]="{title: title}">
  Go To Child Route With Query Params
</a>

И в вашем 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 с private BehaviorSubject, который будет отображаться как Observable, вызвав для него метод asObservable.Его значение можно установить, выставив метод (setChildProperty), который по существу вызовет метод next с обновленным значением childProperty:

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);
  }

}

Затем вы можете внедрить его как в ParentComponent и в вашем ChildComponent:

В 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);
  }

}

И в вашем 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)
    );
  }

  ...

}
0 голосов
/ 05 декабря 2018

Я думаю, что вам не хватает '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

@Component({
  selector: 'child',
  template: `<h1>{{ title }}</h1>`
})
export class ChildComponent {...}       // Be sure to spell it right as yours were ChildComponet - missing 'n'

ОБНОВЛЕНИЕ согласно разъяснениям пользователя в этой теме

Добавил Deck Stackblitz для справки (Проверьте консоль)

Если вы хотите получить доступ к ChildComponent, который отображается в родительском компоненте <router-outlet>, вы можете сделать это, используя (активировать), поддерживаемыйсвойство router-outlet :

Розетка маршрутизатора будет генерировать событие активации каждый раз, когда создается новый компонент

Angular Docs

Шаблон 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' 
    }

}

Результат будет отличаться в зависимости от посещенной страницы у детей вашего родителя

Если вы посетите Child1Component , вы получите его экземпляр Child1Component {title: "hi"}

Если вы посетите Child2Component , вы получите его экземпляр Child2Component {name: "Angular"}

Эти результаты затем будут отражены на консоли onActivate (событие) вашего ParentComponent для доступа к

0 голосов
/ 05 декабря 2018

Убедитесь, что в шаблоне parent.component.html вы добавили тег <child></child>.

...