javascript - Establecer propiedad del componente hijo desde el padre antes de que se renderice la vista
Estoy intentando establecer la propiedad de un componente hijo desde su padre antes de que se renderice su vista.
Ahora uso el decorador ViewChildren en el componente padre, pero en este caso es demasiado tarde, porque la vista de los hijos tiene que usar los datos que vienen del padre.
Entonces, la clase grid mantiene la referencia completa del objeto grid, y quiero enlazar de grid-header a grid-header-item.
HTML raíz:
<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>
Componente padre:
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);
}
}
componente hijo:
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);
}
}
componente hijo html:
<span class="item" (click)="grid.onSortBy(name);">
{{name}} <span *ngIf="grid.sort == name" class="fa" [ngClass]="grid.getDirection(name)"></span>
</span>
Sé que, si agrego [grid]="grid" al elemento grid-header-item funciona, pero creo que esto es un exceso, porque todos los hijos de grid-header tienen que obtener esta referencia, así que esto es redundante.
<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>
Respuesta #1
Dado que Angular2 tiene un sistema de inyección de dependencias basado en el árbol de componentes, podemos simplemente inyectar la instancia del componente padre en el componente hijo:
grid-header.component.ts
export class GridHeaderItemComponent implements OnInit {
public grid;
@Input() name: string = '';
constructor(private parent: GridHeaderComponent) { }
y luego asignar la propiedad parent.grid a la propiedad local grid dentro de ngOnInit
grid-header.component.ts
public ngOnInit() {
this.grid = this.parent.grid;
}
También puedes verlo en acción en Ejemplo de Plunker
Respuesta #2
Con esta solución tendrás acceso a los datos en el ngAfterViewInit, pero no tendrás "dependencia circular" (padre-><-hijo). Si necesitas una comunicación más detallada, intenta usar eventos o un servicio compartido.
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;
});
}}
Y en el componente contenedor de la cuadrícula, tienes algo como esto:
@Component({
selector: 'my-app',
template: `<grid-header [grid]="grid"></grid-header>`,
})
//...
