So, I have a component that renders several components dynamically, with this template:
After studying the different approaches that people gave me, I found the solution on the async
pipe. But, it took me a while to understand how to implement it.
Solution:
// Declaring the Promise, yes! Promise!
filtersLoaded: Promise<boolean>;
// Later in the Component, where I gather the data, I set the resolve() of the Promise
this.getFiltersSubscription = this.getFilters().subscribe(
(filters) => {
this.filters = filters;
log.info('API CALL. getting filters');
this.filtersLoaded = Promise.resolve(true); // Setting the Promise as resolved after I have the needed data
}
);
// In this listener triggered by the dynamic components when instanced,
// I pass the data, knowing that is defined because of the template change
// 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);
}
}
);
In the template, I use the async
pipe that needs an Observable
or a Promise
<div *ngIf="filtersLoaded | async">
<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>
</div>
NOTE:
async
pipe need an Observable
or a Promise
from what I understood, that's why the only way to make it work was by creating a Promise
resolver
approach because it's used when you arrive to the component through Angular's routing. This component is part of a larger component and it's not instanced through routing like any other normal component. (Tried that approach though, worked a bit with it, didn't do the job)You could use a resolver
to ensure those data are loaded (or your filters have been initialized) before the route is activated.
https://blog.thoughtram.io/angular/2016/10/10/resolving-route-data-in-angular-2.html
https://angular.io/api/router/Resolve
<p class="p-large">{{homeData?.meta[0].site_desc}}</p>
Just Used a "?" after the variable that has been getting loaded with data from the server.
home.component.ts
import { Component, OnInit } from '@angular/core';
import { HomeService } from '../services/home.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
public homeData: any;
constructor(private homeService: HomeService) {}
ngOnInit(): void {
this.homeService.getHomeData().subscribe( data => {
this.homeData = data[0];
}, error => {
console.log(error);
});
}
}