I have the following data which originally comes from Firebase.
const agendaDates = ['2022-12-10', '2022-12-11', '2022-12-12', '2022-12-13']
const events = [
{
id: '001',
fromDate: '2022-12-10',
toDate: '2022-12-11',
},
{
id: '002',
fromDate: '2022-12-12',
toDate: '2022-12-13',
},
{
id: '003',
fromDate: '2022-12-12',
toDate: '2022-12-12',
},
]
I would to combine this data to achieve the following result :
const result = [
{
"agendaDate": "2022-12-10",
"id": "001",
"fromDate": "2022-12-10",
"toDate": "2022-12-11"
},
{
"agendaDate": "2022-12-11",
"id": "001",
"fromDate": "2022-12-10",
"toDate": "2022-12-11"
},
{
"agendaDate": "2022-12-12",
"id": "002",
"fromDate": "2022-12-12",
"toDate": "2022-12-13"
},
{
"agendaDate": "2022-12-12",
"id": "003",
"fromDate": "2022-12-12",
"toDate": "2022-12-12"
},
{
"agendaDate": "2022-12-13",
"id": "002",
"fromDate": "2022-12-12",
"toDate": "2022-12-13"
}
]
My actual function iterates over agendaDates with array.map() which is not working if there are multiple events on the same day.
private createAgenda(): Observable<any[]> {
return combineLatest([of(agendaDates), of(events)],
(agendaDates, events) => (
agendaDates.map(
agDate => (
{
agendaDate: agDate, ...events.find(
event => {
return (this.isDateInRange(agDate, event.fromDate, event.toDate)) ? event : false
}
)
}
)
).filter(ev => ev.id != null)
)
)
}
Helper to check if date is in range
private isDateInRange(date: string, startDate: string, endDate: string): boolean {
if (date !== undefined && startDate !== undefined && endDate !== undefined) {
return (new Date(date) >= new Date(startDate) && new Date(date) <= new Date(endDate))
} else return false
}
What is the best option to get there?
Given these are simulating the results from Firebase:
type Event = {
id: string;
fromDate: string;
toDate: string;
};
type EventWithAgendaDate = Event & { agendaDate: string };
const agendaDates: Observable<string[]> = of([
'2022-12-10',
'2022-12-11',
'2022-12-12',
'2022-12-13',
]);
const events: Observable<Event[]> = of([
{
id: '001',
fromDate: '2022-12-10',
toDate: '2022-12-11',
},
{
id: '002',
fromDate: '2022-12-12',
toDate: '2022-12-13',
},
{
id: '003',
fromDate: '2022-12-12',
toDate: '2022-12-12',
},
]);
You can't just loop over one array or the other, since you're trying to find all combinations of an agenda date matching an event. You'll need to test all possibilities. Of course this can be optimized if the arrays are sorted, but I'll show you the general idea.
getEventsWithAgendaDates([agendaDates, events]: [
string[],
Event[]
]): EventWithAgendaDate[] {
const result: EventWithAgendaDate[] = [];
for (const agendaDate of agendaDates) {
for (const event of events) {
if (this.isDateInRange(agendaDate, event.fromDate, event.toDate))
result.push({ agendaDate, ...event });
}
}
return result;
}
private createAgenda(): Observable<EventWithAgendaDate[]> {
return combineLatest([agendaDates, events]).pipe(
map((r) => this.getEventsWithAgendaDates(r))
);
}
demo: https://stackblitz.com/edit/angular-ivy-b9emtt?file=src/app/app.component.ts