Considering this issue as a good example when smart and dumb components are useful.
As you wrote yourself - managing a state is important here and its super easy if you split your component into two - smart and dumb components.
Smart component will prepare all the data while dumb component will render it.
Example
smart.component.ts:
entries: Observable<any>;
loading: false;
getEntries(){
this.loading = true;
this.entries = this.entryservice.getAventry().pipe(
map(data => {
return data.map(e => {
return {
id: e.payload.doc.id,
...e.payload.doc.data() as {}
} as Entrymodel;
})
}),
map(this.setCalendar),
finalise(() => this.loading = false)
);
}
setCalendar(entries){
return entries.forEach(element => {
let start = element.startDate.year + "-" + element.startDate.month + "-" + element.startDate.day;
let end = element.endDate.year + "-" + element.endDate.month + "-" + element.endDate.day;
var startDate = new Date(start);
var endDate = new Date(end);
var title = element.info + " " + element.surname;
this.events = [
...this.events,
{
title: title ,
start: startOfDay(startDate),
end: endOfDay( endDate),
color: {
primary: element.color,
secondary: element.color
},
draggable: false,
resizable: {
beforeStart: false,
afterEnd: false,
},
cssClass: element.surname,
},
];
});
smart.component.html:
<app-dumb-component
[entries]="entries | async"
[loading]="loading"
></app-dumb-component>
dumb-component.ts:
@Input('entries') entries: any[];
@Input('loading'): boolean;
dumb.component.html:
<div *ngIf="!loading; else loading"> ... </div>
<ng-template #loading>
// spinner
</ng-template>
p.s. here for simplicity I store state inside a smart component (while usually we use stores for this) and approach is in general just an example, since the whole architecture of this should be determined how data flows back and forward.
EDIT
What I just noticed you are you are using a real time database, right? (probably Firebase - will add a tag to your post. Please change it if it is not Firebase). And that changes the concept. With normal database like SQL, when you make a HTTP call it will return you once - response or error. While with real time database, you get a stream, like a web socket. Meaning you must treat that as a stream because it can return you values at any time in the future.
So what you asked - you need to get events based on results on entries
stream. And that stream can push values at any time. So what you can do - map entries
to events
:
smart.component.ts:
entries: Observable<any>;
loading: false;
getEntries(){
this.loading = true;
this.events = this.entryservice.getAventry().pipe(
map(data => {
return data.map(e => {
return {
id: e.payload.doc.id,
...e.payload.doc.data() as {}
} as Entrymodel;
})
}),
map(this.setCalendar),
finalise(() => this.loading = false)
);
}
setCalendar(entries){
return entries.map(element => {
let start = element.startDate.year + "-" + element.startDate.month + "-" + element.startDate.day;
let end = element.endDate.year + "-" + element.endDate.month + "-" + element.endDate.day;
var startDate = new Date(start);
var endDate = new Date(end);
var title = element.info + " " + element.surname;
return {
title: title ,
start: startOfDay(startDate),
end: endOfDay( endDate),
color: {
primary: element.color,
secondary: element.color
},
draggable: false,
resizable: {
beforeStart: false,
afterEnd: false,
},
cssClass: element.surname,
},
];
});
Changes in setCalendar function - entries.forEach
changed to entries.map
and this.events = [ ...this.events,
to return
smart.component.html:
<app-dumb-component
[events]="events | async"
[loading]="loading"
></app-dumb-component>
Now at this point, loading
property will be useful only for first connection because later it will emit immediately.