在视图呈现之前从父级设置子组件属性

Posted

技术标签:

【中文标题】在视图呈现之前从父级设置子组件属性【英文标题】:Set child component property from parent before view rendered 【发布时间】:2017-11-14 03:43:03 【问题描述】:

我正在尝试在其视图呈现之前从其父级设置子组件属性。

现在我在父组件中使用 ViewChildren 装饰器,但在这种情况下为时已晚,因为子视图必须使用来自父组件的数据。

所以grid类持有grid对象的完整引用,我想从grid-header绑定到grid-header-item。

html

<grid-header [grid]="grid" [ngClass.xs]="'search-open': grid.searchToggle, 'mobile-header': true">
    <grid-header-item fxFlex="75px" name="Level"></grid-header-item>
    <grid-header-item fxFlex name="Type"></grid-header-item>
    <grid-header-item fxFlex name="Stats"></grid-header-item>
</grid-header>

父组件:

import  Component, ViewChildren, forwardRef, Input, OnInit, AfterViewInit, OnDestroy  from '@angular/core';

import  
    StorageService, 
 from '../../_shared';

import  
    GridHeaderItemComponent, 
 from './';

@Component(
    selector: 'grid-header',
    templateUrl: './grid-header.component.html',
    styleUrls: ['./grid-header.component.scss'],
    host: 'fxLayout': 'row'
)
export class GridHeaderComponent implements OnInit, AfterViewInit 

    constructor(storage: StorageService) 

    @Input() grid = null;
    @ViewChildren(forwardRef(() => GridHeaderItemComponent)) private headerItem;

    public ngOnInit() 

    

    public ngAfterViewInit() 

        console.log(this.headerItem);

        setTimeout(() => 
            this.headerItem.grid = this.grid;
        , 0);
    

子组件:

import  Component, HostBinding, Input, OnInit, OnDestroy  from '@angular/core';

import  
    StorageService, 
 from '../../_shared';

@Component(
    selector: 'grid-header-item',
    templateUrl: './grid-header-item.component.html',
    styleUrls: ['./grid-header-item.component.scss'],
    host: 

    
)
export class GridHeaderItemComponent implements OnInit 
    public grid;

    constructor(storage: StorageService) 

    @Input() name: string = '';

    public ngOnInit() 
        console.log(this.name);
    

    public ngOnDestroy() 
        // this.storage.unsubscribeAll(this.class);
    

子组件 html:

<span class="item" (click)="grid.onSortBy(name);">
    name <span *ngIf="grid.sort == name" class="fa" [ngClass]="grid.getDirection(name)"></span>
</span>

我知道,如果我将 [grid]="grid" 添加到 grid-header-item 元素它可以工作,但我认为这是一个开销,因为所有 grid-header 子项都必须获取此引用,所以这是多余的.

<grid-header [grid]="grid" [ngClass.xs]="'search-open': grid.searchToggle, 'mobile-header': true">
    <grid-header-item fxFlex="75px" [grid]="grid" name="Level"></grid-header-item>
    <grid-header-item fxFlex [grid]="grid" name="Type"></grid-header-item>
    <grid-header-item fxFlex [grid]="grid" name="Stats"></grid-header-item>
</grid-header>

【问题讨论】:

它看起来怎么样?我还没有听说过如何给它的孩子注入父母。 不幸的是父级通过@input装饰器获取网格对象,所以当子级注入父级时,网格属性为null。 @yurzui 你是对的,我找到了 componentFactory 的其他解决方案,但你的答案更接近问题。请发一个回答,我会接受的。 【参考方案1】:

由于 angular2 有基于组件树的依赖注入系统,我们可以简单地在子组件中注入父组件实例:

grid-header.component.ts

export class GridHeaderItemComponent implements OnInit 
    public grid;
    @Input() name: string = '';

    constructor(private parent: GridHeaderComponent)  

然后将parent.grid 属性分配给ngOnInit 中的本地grid 属性

grid-header.component.ts

 public ngOnInit() 
   this.grid = this.parent.grid;
 

您还可以在 Plunker Example

中看到它的实际效果

【讨论】:

【参考方案2】:

使用此解决方案,您将可以访问 ngAfterViewInit 中的数据,但不会有“循环依赖”(父级->

gridHeader.component.ts

@Component(
    selector: 'grid-header-item',
    template: `
        <span class="item" (click)="grid.onSortBy(name);">
            name <span *ngIf="grid.sort == name">Sortby</span>
        </span>
    `
)
export class GridHeaderItemComponent
    @Input() name: string = '';
    public grid:any = ;


@Component(
    selector: 'grid-header',
    template:  `
    <grid-header-item fxFlex="75px" name="Level"></grid-header-item><br/>
    <grid-header-item fxFlex name="Type"></grid-header-item><br/>
    <grid-header-item fxFlex name="Stats"></grid-header-item>`
)
export class GridHeaderComponent implements AfterViewInit   
  @ViewChildren(GridHeaderItemComponent) private headers:Array<headerItem>;   
  @Input() grid = ;
    ngAfterViewInit() 
      this.headers.forEach(h=>//it can be a QueryList too
        h.grid=this.grid;
    );

在网格的包装组件中,你有这样的东西:

@Component(
  selector: 'my-app',
  template: `<grid-header [grid]="grid"></grid-header>`,
)
//...

【讨论】:

以上是关于在视图呈现之前从父级设置子组件属性的主要内容,如果未能解决你的问题,请参考以下文章

如何使用Vue从父级中的多个子组件中获取值?

angular 5 从父组件设置子组件属性

有办法去掉从父级元素继承下来的 CSS 样式吗

有办法去掉从父级元素继承下来的 CSS 样式吗

从Angular 2中的子组件更新父组件属性

如何从父级修改组件的样式?