Angular - Esperar a recibir datos antes de cargar plantilla
Entonces, tengo un componente que renderiza varios componentes dinámicamente, con esta plantilla:
<div [saJquiAccordion]="{active: group.value['collapsed']}" *ngFor="let group of filterGroupsTemplate | keysCheckDisplay;">
<div>
<h4>{{group.key | i18n}}</h4>
<form id="ibo-{{group.key}}" class="form-horizontal" autocomplete="off" style="overflow: initial">
<fieldset *ngFor="let field of group.value | keys">
<ng-container *ngComponentOutlet="fieldSets[field.value.template];
ngModuleFactory: smartadminFormsModule;"></ng-container>
</fieldset>
</form>
</div>
</div>
El caso es que los datos necesarios para rellenar esos componentes los estoy obteniendo de una llamada a la API:
this.getFiltersSubscription = this.getFilters().subscribe(
(filters) => {
this.filters = filters;
log.info('API CALL. getting filters');
// Sending data to fieldform components
this.iboService.updateIBOsRankList(filters['iboRank'].data);
this.iboService.updateIBOsNewsletterOptions(filters['iboNewsletter'].data);
this.iboService.updateIBOsTotalOrders(filters['iboTotalOrders'].data);
}
);
Así que, una vez tengo mis datos, disparo un servicio Observable al que están suscritos mis componentes, que procesarán los datos recogidos.
PROBLEMA:
**Si la llamada a la API se realiza antes de que se carguen todos los componentes, estaré disparando estos métodos de servicio pasando datos pero nadie estará suscrito a esos Observables.
Una aproximación sería:
Cargar los datos primero, y sólo cuando tenga los datos cargados, renderizar la plantilla y, por tanto, renderizar todos estos componentes dinámicamente y sólo entonces disparar estos métodos de servicio (Observables).
No quiero hacer una llamada al API por cada componente, porque pueden ser como 60 componentes, prefiero perder abstracción del código pero prefiero hacer algo así:
// Listens to field's init and creates the fieldset triggering a service call that will be listened by the field component
this.iboService.initIBOsFilters$.subscribe(
(fieldName) => {
if (fieldName === 'IBOsRankSelectorFieldComponent') {
log.data('inside initIBOsFilters$ subscription, calling updateIBOsFilters()', fieldName);
this.iboService.updateIBOsRankList(this.filters['iboRank'].data); // HERE I'M PASSING DATA TO THE COMPONENT RENDERED DYNAMICALY. BUT IF this.filters IS UNDEFINED, IT BREAKS
}
}
);
Para hacer esto, necesito asegurarme de que this.filters
está definido y así, llego a la conclusión:
**¿Cómo puedo esperar a que termine la llamada a la API y se defina this.filters
antes de renderizar el html de mi plantilla?
Lo siento si mi pregunta es un poco larga, si necesita más detalles sólo hágamelo saber.
Gracias.
Después de estudiar los diferentes enfoques que la gente me dio, encontré la solución en la tubería
async
. Pero, me tomó un tiempo entender cómo implementarlo.Solución:
En la plantilla, utilizo la tubería
async
que necesita unObservable
o unPromise
.NOTA:
async
necesita unObservable
o unaPromise
por lo que he entendido, por eso la única forma de hacerla funcionar era creando una `Promiseresolver
porque se utiliza cuando se llega al componente a través del enrutamiento de Angular. Este componente es parte de un componente mayor y no se instancian a través de enrutamiento como cualquier otro componente normal. (Aunque he probado ese enfoque, he trabajado un poco con él, pero no ha funcionado)Podrías utilizar un
resolver
para asegurarte de que esos datos están cargados (o tus filtros han sido inicializados) antes de que se active la ruta.https://blog.thoughtram.io/angular/2016/10/10/resolving-route-data-in-angular-2.html
https://angular.io/api/router/Resolve