【问题标题】: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 的其他解决方案,但你的答案更接近问题。请发一个回答,我会接受的。

标签: javascript angular typescript


【解决方案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>`,
    })
    //...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-19
      相关资源
      最近更新 更多