Estoy tratando de aprender Angular 2.
Me gustaría acceder a un componente secundario desde un componente primario utilizando la Anotación @ViewChild .
Aquí algunas líneas de código:
En BodyContent.ts tengo:
import {ViewChild, Component, Injectable} from 'angular2/core';
import {FilterTiles} from '../Components/FilterTiles/FilterTiles';
@Component({
selector: 'ico-body-content'
, templateUrl: 'App/Pages/Filters/BodyContent/BodyContent.html'
, directives: [FilterTiles]
})
export class BodyContent {
@ViewChild(FilterTiles) ft:FilterTiles;
public onClickSidebar(clickedElement: string) {
console.log(this.ft);
var startingFilter = {
title: 'cognomi',
values: [
'griffin'
, 'simpson'
]}
this.ft.tiles.push(startingFilter);
}
}
mientras que en FilterTiles.ts :
import {Component} from 'angular2/core';
@Component({
selector: 'ico-filter-tiles'
,templateUrl: 'App/Pages/Filters/Components/FilterTiles/FilterTiles.html'
})
export class FilterTiles {
public tiles = [];
public constructor(){};
}
Finalmente aquí las plantillas (como se sugiere en los comentarios):
BodyContent.html
<div (click)="onClickSidebar()" class="row" style="height:200px; background-color:red;">
<ico-filter-tiles></ico-filter-tiles>
</div>
FilterTiles.html
<h1>Tiles loaded</h1>
<div *ngFor="#tile of tiles" class="col-md-4">
... stuff ...
</div>
La plantilla FilterTiles.html está cargada correctamente en la etiqueta ico-filter-tiles (de hecho, puedo ver el encabezado).
Nota: la clase BodyContent se inyecta dentro de otra plantilla (Body) usando DynamicComponetLoader: dcl.loadAsRoot (BodyContent, '# ico-bodyContent', inyector):
import {ViewChild, Component, DynamicComponentLoader, Injector} from 'angular2/core';
import {Body} from '../../Layout/Dashboard/Body/Body';
import {BodyContent} from './BodyContent/BodyContent';
@Component({
selector: 'filters'
, templateUrl: 'App/Pages/Filters/Filters.html'
, directives: [Body, Sidebar, Navbar]
})
export class Filters {
constructor(dcl: DynamicComponentLoader, injector: Injector) {
dcl.loadAsRoot(BodyContent, '#ico-bodyContent', injector);
dcl.loadAsRoot(SidebarContent, '#ico-sidebarContent', injector);
}
}
El problema es que cuando trato de escribir ften el registro de la consola, obtengo undefined, y por supuesto obtengo una excepción cuando intento insertar algo dentro de la matriz de "mosaicos": 'no hay mosaicos de propiedades para "indefinido"' .
Una cosa más: el componente FilterTiles parece estar cargado correctamente, ya que puedo ver la plantilla html para él.
¿Cualquier sugerencia? Gracias
fuente

ftno se establecería en el constructor, pero en un controlador de eventos click ya estaría configurado.loadAsRoot, que tiene un problema conocido con la detección de cambios. Solo para asegurarte de usarloadNextToLocationoloadIntoLocation.loadAsRoot. Una vez que lo reemplacé conloadIntoLocationel problema se resolvió. Si haces tu comentario como respuesta, puedo marcarlo como aceptadoRespuestas:
Tuve un problema similar y pensé en publicar en caso de que alguien cometiera el mismo error. Primero, una cosa a considerar es
AfterViewInit; debe esperar a que se inicialice la vista antes de poder acceder a su@ViewChild. Sin embargo, mi@ViewChildtodavía regresaba nulo. El problema fue mi*ngIf. La*ngIfdirectiva estaba matando mi componente de controles, así que no pude hacer referencia a él.Espero que ayude.
EDITAR
Como se menciona en @Ashg a continuación , una solución es usar en
@ViewChildrenlugar de@ViewChild.fuente
ngClass+hiddenclass en lugar dengIf. Eso funciono. ¡Gracias!El problema como se mencionó anteriormente es el
ngIfque hace que la vista sea indefinida. La respuesta es usar enViewChildrenlugar deViewChild. Tuve un problema similar en el que no quería que se mostrara una cuadrícula hasta que se hayan cargado todos los datos de referencia.html:
Código de componente
Aquí estamos utilizando
ViewChildrenen el que puede escuchar los cambios. En este caso, cualquier niño con la referencia#searchGrid. Espero que esto ayude.fuente
this.SearchGridpropiedades que debe usarsetTimeout(()=>{ ///your code here }, 1);para evitar la sintaxis Excepción: la expresión ha cambiado después de que se verificó*ngIffunciona, y después de renderizar podemos guardar un ElementRef de los componentes dinámicos.Podrías usar un setter para
@ViewChild()Si tiene un contenedor ngIf, se llamará al setter con undefined, y luego nuevamente con una referencia una vez que ngIf le permita renderizar.
Sin embargo, mi problema era otra cosa. No había incluido el módulo que contenía mis "FilterTiles" en mi app.modules. La plantilla no arrojó un error, pero la referencia siempre fue indefinida.
fuente
FilterTiles. He encontrado ese problema por esa razón antes.@ViewChild('paginator', {static: false})Esto funcionó para mí.
Mi componente llamado 'my-component', por ejemplo, se mostró usando * ngIf = "showMe" así:
Entonces, cuando el componente se inicializa, el componente aún no se muestra hasta que "showMe" sea verdadero. Por lo tanto, mis referencias @ViewChild no estaban definidas.
Aquí es donde utilicé @ViewChildren y la QueryList que devuelve. Vea el artículo angular en QueryList y una demostración de uso de @ViewChildren .
Puede usar la Lista de consultas que devuelve @ViewChildren y suscribirse a cualquier cambio en los elementos a los que se hace referencia utilizando rxjs como se ve a continuación. @ViewChild no tiene esta habilidad.
Espero que esto ayude a alguien a ahorrar algo de tiempo y frustración.
fuente
.take(1).subscribe(), pero excelente respuesta, ¡muchas gracias!Mi solución era usar en
[style.display]="getControlsOnStyleDisplay()"lugar de*ngIf="controlsOn". El bloque está ahí pero no se muestra.fuente
Lo que resolvió mi problema fue asegurarme de que
staticestaba configurado enfalse.Con
staticdesactivado,@ViewChildAngular actualiza la referencia cuando*ngIfcambia la directiva.fuente
Mi solución a esto fue reemplazar
*ngIfcon[hidden]. Lo malo era que todos los componentes secundarios estaban presentes en el código DOM. Pero funcionó para mis requisitos.fuente
En mi caso, tenía un setter de variables de entrada usando
ViewChild, yViewChildestaba dentro de una*ngIfdirectiva, por lo que el setter intentaba acceder antes que el*ngIfrenderizado (funcionaría bien sin el*ngIf, pero no funcionaría si siempre estuviera configurado en cierto con*ngIf="true").Para resolverlo, utilicé Rxjs para asegurarme de que cualquier referencia al
ViewChildesperado hasta que se iniciara la vista. Primero, cree un Asunto que se complete después de ver init.Luego, cree una función que tome y ejecute una lambda después de que el sujeto se complete.
Finalmente, asegúrese de que las referencias a ViewChild usen esta función.
fuente
Debe funcionar
Pero como dijo Günter Zöchbauer , debe haber algún otro problema en la plantilla. He creado un poco Relevant-Plunkr-Answer . Por favor, compruebe la consola del navegador.
boot.ts
filterTiles.ts
Funciona a las mil maravillas. Por favor revise sus etiquetas y referencias.
Gracias...
fuente
Esto funciona para mí, vea el ejemplo a continuación.
fuente
Tuve un problema similar, donde
ViewChildestaba dentro de unaswitchcláusula que no estaba cargando el elemento viewChild antes de que fuera referenciado. Lo resolví de una manera semi-hacky pero envolviendo laViewChildreferencia en unasetTimeoutque se ejecutó de inmediato (es decir, 0 ms)fuente
Mi solución a esto fue mover el ngIf desde el exterior del componente secundario al interior del componente secundario en un div que envolvía toda la sección de html. De esa manera, todavía se ocultaba cuando era necesario, pero podía cargar el componente y podía hacer referencia a él en el padre.
fuente
Lo arreglo simplemente agregando SetTimeout después de establecer visible el componente
Mi HTML:
My Component JS
fuente
En mi caso, sabía que el componente hijo siempre estaría presente, pero quería alterar el estado antes de que el niño se inicializara para ahorrar trabajo.
Elijo probar el niño hasta que apareció y hacer cambios de inmediato, lo que me ahorró un ciclo de cambio en el componente hijo.
Alertativamente, puede agregar un número máximo de intentos o agregar algunos ms de retraso al
setTimeout.setTimeoutefectivamente lanza la función al final de la lista de operaciones pendientes.fuente
Un tipo de enfoque genérico:
Puede crear un método que esperará hasta
ViewChildque esté listoUso:
fuente
Para mí, el problema era que hacía referencia a la ID del elemento.
En lugar de esto:
fuente
Si usa Ionic, deberá usar el
ionViewDidEnter()gancho del ciclo de vida. Iónica corre un poco de materia adicional (principalmente relacionados con la animación) que normalmente provoca errores inesperados como éste, de ahí la necesidad de algo que se ejecuta despuésngOnInit,ngAfterContentInity así sucesivamente.fuente
Aquí hay algo que funcionó para mí.
Así que básicamente establezco una verificación cada segundo hasta que se
*ngIfhace realidad y luego hago mis cosas relacionadas con elElementRef.fuente
La solución que funcionó para mí fue agregar la directiva en las declaraciones en app.module.ts
fuente