访问父组件中的属性


74

我在顶级组件中有一个属性,该属性使用了来自HTTP源的数据,如下所示(这在一个名为的文件中app.ts):

import {UserData} from './services/user-data/UserData';

Component({
    selector: 'app', // <app></app>
    providers: [...FORM_PROVIDERS],
    directives: [...ROUTER_DIRECTIVES],
    pipes: [],
    template: require('./app.html')
})
@RouteConfig([
    // stuff here
])

export class App {
    // Please note that UserData is an Injectable Service I have written
    userStatus: UserStatus;

    constructor(private userData: UserData) {
        this.userStatus = new UserStatus();
    }

    ngOnInit() {
        this.userData.getUserStatus()
            .subscribe(
            (status) => {
                this.userStatus = status; // I want to access this in my Child Components...
            },
            (err) => {console.log(err);},
            () => {console.log("User status complete");            }
        );
    }
}

现在,我有另一个Component,它是顶级Component的直接子代,并且我想在其中访问父代的属性userStatus',这里是子代:

Component({
    selector: 'profile',
    template: require('app/components/profile/profile.html'),
    providers: [],
    directives: [],
    pipes: []
})

export class Profile implements OnInit {
    constructor() {

    }

    ngOnInit() {
        // I want to have access with the parent App Component, 'userStatus' propety here... I only want to read this property
    }
}

现在在Angular 1.x中,这很容易,因为我可以$parent在我的子控制器中引用该文件,也可以(将ANTI PATTERN ALERT !!!)引用到我的表中$rootScope

在Angular 2中访问父级的最佳方法是什么?

Answers:


77

有不同的方法:

export class Profile implements OnInit {
constructor(@Host() parent: App) {
  parent.userStatus ...
}
  • 数据绑定
export class Profile implements OnInit {
  @Input() userStatus:UserStatus;
  ...
}

<profile [userStatus]="userStatus">

1
Angular2与性能有关。Angular2已(或将要完成,但仍有很多工作要做)已经过优化,因此即使大型应用程序也能很好地运行。对TS和Dart(比JS更适合于大型应用程序)的支持也带来了一些样板和局限性,但这也允许分析代码并进行更明智的优化。没有阴影就没有光……
君特Zöchbauer

3
@GünterZöchbauer,很高兴您指出的“缺点:紧密耦合@Inputs,但是我希望您承认使用Services的缺点-即,与Angular Dependency Injection系统的便利性有关。读者应注意,具有较高的链接度,扇出/输入同样危险。使用直接输入链,您至少要遵守LoD(《德米特律法》),但是我会为每个模块设计一个Sandbox或Director / Facade,以便它们不会扇出大量的服务;因为那是您真正被淘汰的时候。

紧密耦合问题肯定是与使用@Host() parent: App而不是数据绑定技术有关的@Input()
qaisjp

注意:如果需要@Host()是可选的,则您的代码必须为@Optional @Host() parent: App
MOH3N

39

我有同样的问题,但解决方法有所不同。我不知道这是否是一个好方法,但是它可以很好地满足我的需求。

我在子组件的构造函数上使用了@Inject,如下所示:

import { Component, OnInit, Inject } from '@angular/core';
import { ParentComponent } from '../views/parent/parent.component';

export class ChildComponent{
    constructor(@Inject(ParentComponent) private parent: ParentComponent){

    }

    someMethod(){
        this.parent.aPublicProperty = 2;
    }
}

这对我有用,您只需要将要调用的方法或属性声明为public。

就我而言,AppComponent处理路由,并且我在菜单项中使用徽章来提醒用户新的未读消息可用。因此,每当用户阅读一条消息时,我都希望刷新该计数器,所以我调用refresh方法,以便导航菜单上的数字被新值更新。这可能不是最好的方法,但我喜欢它的简单性。


2
这是一个很好的解决方法,但不是解决方案,因为在大多数情况下,组件父类会随您想重用组件的不同而变化。
Guillaume LeMière,

1
请注意,如果您在同一文件中但在子文件之后定义了ParentComponent,则需要将其移动到要在子文件之上定义的位置,或者如果有循环引用,则需要使用forwardRef。即@Inject(forwardRef(() => ParentComponent)) parent: ParentComponent
议会

@Inject(ParentComponent)强制性的吗?由于指定了类型,这似乎是不必要的,我遗漏了什么吗?
PeterPan666 '19

如果您在子页面上加载网站,那么父属性将是未定义的,如果它是通过异步操作加载的,则需要处理该方面。
肖恩

15

你可以:

  • userStatus为子组件定义一个参数,并在从父组件使用该组件时提供值:

    @Component({
      (...)
    })
    export class Profile implements OnInit {
      @Input()
      userStatus:UserStatus;
    
      (...)
    }
    

    并在父母中:

    <profile [userStatus]="userStatus"></profile>
    
  • 将父级注入子级组件:

    @Component({
      (...)
    })
    export class Profile implements OnInit {
      constructor(app:App) {
        this.userStatus = app.userStatus;
      }
    
      (...)
    }
    

    注意它们之间的循环依赖性。


1
这对我来说没有多大意义。您在父类Profile上拥有一个属性,然后说您将其注入到子组件Profile中?!?!?看起来您正在使用配置文件的选择器将名为userSatus的绑定绑定到组件,但是您正在将App类注入名称为Profile no no的组件。根据您的描述,我可以想象您有一个Parent类(一个定义userStatus的类)和一个子类,一个在其构造函数中设置局部值的类,您应该将Parent注入构造函数中。是这样吗?
古纳德

13

我制作了一个通用组件,需要在其中引用使用它的父级。这是我想出的:

在我的组件中,我做了一个@Input:

@Input()
parent: any;

然后在父级中使用此组件:

<app-super-component [parent]="this"> </app-super-component>

在超级组件中,我可以使用来自父级的任何公共事物:

属性:

parent.anyAttribute

职能 :

parent[myFunction](anyParameter)

当然,私人物品将无法访问。


2

在Angular 6上,我通过构造函数注入父级来访问父级属性。不是最好的解决方案,但它可以工作:

 constructor(@Optional() public parentComponentInjectionObject: ParentComponent){
    // And access like this:
    parentComponentInjectionObject.thePropertyYouWantToAccess;
}

1
但是,然后您必须知道您的父母是谁
mila

1
这将创建循环依赖关系。
gearsandcode '19

这是Angular Material的源代码中广泛使用的方法。仅当您将子代注入到父代中时,它才会创建循环依赖。
tommyc38

2

由于亲子互动并不是一件容易的事。但是,通过在子组件中具有父组件的引用,交互会容易得多。在我的方法中,您需要首先通过调用子组件的功能来传递父组件的引用。这是此方法的。

子组件代码。

    import { Component, Input,ElementRef,Renderer2 } from '@angular/core';

    import { ParentComponent } from './parent.component';

    @Component({
      selector: 'qb-child',
      template: `<div class="child"><button (click)="parentClickFun()">Show text Of Parent Element</button><button (click)="childClickFun()">Show text Of Child Element</button><ng-content></ng-content></div>`,
      styleUrls: ['./app.component.css']
    })
    export class ChildComponent  {
      constructor(private el: ElementRef,private rend: Renderer2){

      };

      qbParent:ParentComponent; 
      getParent(parentEl):void{
        this.qbParent=parentEl;
        console.log(this.el.nativeElement.innerText);
      }
      @Input() name: string;
      childClickFun():void{
        console.log("Properties of Child Component is Accessed");
      }

      parentClickFun():void{
        this.qbParent.callFun();
      }
    }

这是父组件的代码

import { Component, Input , AfterViewInit,ContentChild,ElementRef,Renderer2} from '@angular/core';

import { ChildComponent } from './child.component';

@Component({
  selector: 'qb-parent',
  template: `<div class="parent"><ng-content></ng-content></div>`,
  styleUrls: ['./app.component.css']
})
export class ParentComponent implements AfterViewInit {
  constructor(private el: ElementRef,private rend: Renderer2){

  };
  @Input() name: string;
  @ContentChild(ChildComponent,{read:ChildComponent,static:true}) qbChild:ChildComponent;

  ngAfterViewInit():void{
    this.qbChild.getParent(this);
  }

  callFun():void{
    console.log("Properties of Parent Component is Accessed");
  }

}

HTML代码

<qb-parent>
  This is Parent
  <qb-child>
    This is Child
  </qb-child>
</qb-parent>

在这里,我们通过调用子组件的函数来传递父组件。下面的链接是此方法的示例。点击这里

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.