简体   繁体   中英

NG2: How can I access parent component generically?

Before I begin please note that I originally asked this question as a feature request at the angular2 github site. However the request was closed and I was advised to post it here. Here I am just repeating my initial request. However you can find some discussion by following the link: https://github.com/angular/angular/issues/10448

I need the ability to obtain a reference to the parent component generically without the child having to know the type of the parent component. Basically I need something like this (pseudocode):

    @Component({
        template: '<child></child>'
        directives: [Child]
    })
    class ParentComponent{}

    @Component({ selector: 'child' })
    class ChildComponent{
        constructor(@Parent() _parent: any){}
    }

Basically I need the _parent field of the ChildComponent to reference the ParentComponent . But notice how the type of _parent is any . It's any because it can be any, literally. ChildComponent is a generic component that can be used by any type of other component. I know there are solutions out there for this problem but they all entail the child knowing the type of the parent. It goes something like this:

    @Component({ selector: 'child' })
    class ChildComponent{
        constructor(_parent: ParentComponent){}
    }

But again, this will not work for me because ChildComponent can be used in any type of other component, and neither one knows the type of the other. So what I need is some generic way to inject into ChildComponent its parent component, as set in the component tree, without ChildComponent knowing the parent type. Does anyone know how I can accomplish this?

You can use Injector API for the same.

For Angular2 latest release and older versions:

import { Injector } from '@angular/core';
import {AppComponent} from "./app.component";

@Component({ selector: 'child' })
class ChildComponent{
     constructor(private inj:Injector){
         let parentComponent = this.inj.get(AppComponent);
         console.log(parentComponent);
     }
}

Using @Input and a little trick to send the this of the parent to the child. I guess you can do it the other way around also, to access child from parent via an @Output

Parent Component

import { Component } from '@angular/core';

@Component({
    selector: 'app-root',
    template: '<app-child [parnt]="var2"></app-child>',
    style: ''
})
export class AppComponent {
    title = 'app works!';
    var1 = "val1";
    var2 = this;
}

Child Component

import { Component, Input, EventEmitter, OnInit } from '@angular/core';

@Component({
  selector: 'app-child',
  template: '{{parnt.var1}}',
  style: ''
})
export class ChildComponent implements OnInit {
  @Input() parnt;
}

You should see "val1" printed, the value of the var1 of the parent printed in the child template.

Thanks to @yurzui for leading me in the right direction... In the end I found a couple of different ways... unfortunately all involve accessing private members which is less than ideal... If anyone knows of a better way, please speak up... thank you

 constructor(private vcRef: ViewContainerRef){
    var parentComponent1 = this.vcRef.injector._view.context;
    console.log(parentComponent1);
    var parentComponent2 = this.vcRef._element.parentView.context;
    console.log(parentComponent2);
    console.log(parentComponent1 === parentComponent2);
  }

Here is how to make it work.

@Component({
    selector: 'child'
})
class ChildComponent{
    constructor( @Optional() public myParent: ParentComponent ){}
}

You can find more info in Angular DI docs

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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