wake-up-neo.com

Angular 6 @Viewchild arbeitet nicht mit Lazy Loading

Hier ist mein Code, der einen Fehler gibt, der den Eigenschaftstitel undefined nicht lesen kann.

Übergeordnete Komponente

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

Und die untergeordnete Komponente ist.

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

     public title = "hi"
     constructor(){}

    }

routing.module.ts ist wie

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

Und gibt Fehler, ist

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

Ich denke, dass Sie 'template' oder 'templateUrl' in Bezug auf das Erstellen einer Komponente vermissen

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'

UPDATE gemäß der Erläuterung des Benutzers in diesem Thread

Hatte eine Stackblitz-Demo hinzugefügt als Referenz (Überprüfen Sie die Konsole)

Wenn Sie auf die ChildComponent zugreifen möchten, die unter dem <router-outlet> der übergeordneten Komponente gerendert wird, können Sie dies durch Verwendung von (aktivieren) der unterstützten Eigenschaft von router-outlet tun:

Ein Router-Ausgang gibt jedes Mal ein Aktivierungsereignis aus, wenn eine neue Komponente instanziiert wird 

Angular Docs

ParentComponent-Vorlage

@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' 
    }

}

Das Ergebnis unterscheidet sich je nach besuchter Seite unter den Kindern Ihrer Eltern.

Wenn Sie Child1Component besuchen, erhalten Sie die Instanz Child1Component {title: "hi"}.

Wenn Sie Child2Component besuchen, erhalten Sie dessen Instanz Child2Component {name: "Angular"}.

Diese Ergebnisse werden dann in der onActivate (event) -Konsole Ihrer ParentComponent angezeigt, damit Sie auf zugreifen können.

11
KShewengger

So soll es nicht funktionieren. Sie können ChildComponent nur in Ihrer ParentComponentNUR abrufen, wenn Sie das <app-child></app-child>-Tag in Ihrer ParentComponent-Vorlage haben.

Etwas wie das:

...

<app-child></app-child>

...

Da Sie jedoch untergeordnetes Routing verwenden und ChildComponent auf den router-outlet Ihres ParentComponent geladen wird, haben Sie mit ViewChild keinen Zugriff darauf.

PS: Sie haben nur Zugriff auf ngAfterViewInit, da ViewChild nur dann als sicher erachtet werden kann, nachdem die View geladen wurde:

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

}

Hier ist ein Working Sample StackBlitz für Ihren Ref, der Ihr Szenario in beiden Fällen veranschaulicht.

PS: Um die ChildComponent-Eigenschaften in Ihrem ParentComponent zu erhalten, müssen Sie beim Routing entweder ein SharedService verwenden, oder Sie müssen die ChildProperty in der Route als QueryParam übergeben und in der ParentComponent mithilfe von lesen ActivatedRoute

AKTUALISIEREN:

Freigeben von Daten mithilfe von Routenabfrageparametern:

Dies macht zwar nicht viel Sinn, aber in Ihrer ChildComponent können Sie einen Link haben, der den Benutzer mit der title-Eigenschaft, die als queryParam übergeben wird, an die ChildComponent weiterleitet. Etwas wie das:

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

Und in Ihrem ParentComponent haben Sie Zugriff auf ActivatedRoute wie folgt:

...
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 verwenden

Erstellen Sie einfach eine SharedService mit einer privateBehaviorSubject, die als Observable verfügbar gemacht würde, indem Sie die asObservable-Methode aufrufen. Ihr Wert kann festgelegt werden, indem eine Methode (setChildProperty) verfügbar gemacht wird, die im Wesentlichen die next-Methode mit dem aktualisierten childProperty-Wert aufruft:

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

}

Sie können es dann sowohl in Ihr ParentComponent als auch in Ihr ChildComponent injizieren:

In ChildComponent setzen Sie den Wert:

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

}

Und in Ihrer ParentComponent erhalten Sie den Wert:

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

  ...

}
3
SiddAjmera

Stellen Sie sicher, dass Sie in Ihrer parent.component.html-Vorlage das <child></child>-Tag hinzugefügt haben.

2
Morema