I have a Angular html template that has a ambiguous dependency between an observable and a piped function. The output of the functions are the events
and schedule$
arrays, respectively.
Problem, the event
array does not load into the html template unless the schedule$
array is also loaded with *ngFor, even when the function for schedule$
(getCalendar()
) is run with ngOnInit()
Questions:
- I no longer have a functional need for
schedule$
so want to completely omit that from my code. Currently, I can't do that because theevent
array's items disappear also. How can I remove theschedule$
*ngFor
without impactingevent
*ngFor
? - What is the root cause of this dependency? Aren't both functions independent?
<div >
CalendarEvent Div from getEvents()
<ul *ngFor="let evnt of events">
<li>Title: {{evnt.title}}</li>
<li>Start: {{evnt.start}}</li>
<li>End: {{evnt.end}}</li>
<li>Creator: {{evnt.created_by}}</li>
</ul>
</div>
<div >
Schedule Div from getCalendar()
<ul *ngFor="let event of schedule$ | async | slice:0:1">
<li>Title: {{event.title}}</li>
<li>Start: {{event.start}}</li>
<li>End: {{event.end}}</li>
</ul>
</div>
My component module where the functions are defined is:
schedule$!: Observable<Schedule[]>;
events: CalendarEvent[] = [];
ngOnInit(): void {
this.getCalendar(),
this.getEvents()
}
public getEvents(): any {
this.apiService.getEvent()
.subscribe(
(data: any) => {
this.events = data;
for (let event of this.events) {
event.start = new Date(event.start);
event.end = new Date(event.end);
}
},
(err:any) => console.error(err),
() => console.log('done loading events')
);
}
public getCalendar(): any {
this.schedule$ = this.apiService.getCalendar().pipe(tap((dataset: any) =>console.log('getCalendar()', dataset)))
}
The API end points used in these functions is the same
public getCalendar(): Observable<Schedule[]> {
return this.http.get<Schedule[]>(`${this.API_URL}/schedule/`,
{
responseType: 'json',
headers: new HttpHeaders().set('Authorization', `Bearer ${this.auth.accessToken}`)
});
}
public getEvent(): Observable<CalendarEvent[]> {
return this.http.get<CalendarEvent[]>(`${this.API_URL}/schedule/`,
{
responseType: 'json',
headers: new HttpHeaders().set('Authorization', `Bearer ${this.auth.accessToken}`)
});
}
The interface are
export interface CalendarEvent<MetaType = any> {
id?: string | number;
start: Date;
end: Date;
title: string;
color?: EventColor;
actions?: EventAction[];
allDay?: boolean;
cssClass?: string;
resizable?: {
beforeStart?: boolean;
afterEnd?: boolean;
};
draggable?: boolean;
meta?: MetaType;
isEditable?: boolean;
created_by?: string;
event_skaper?: string;
event_booker?: string;
}
export interface Schedule {
id: number;
title: string;
start: Date;
end: Date;
created_by: string;
event_skaper: string;
event_booker: string;
}
CodePudding user response:
First of all, this is weird that you have 2 of the same API calls in service that should return different types without any pipes.
Second, I recommend you transform the simple events
array to Observable
or BehaviorSubject.
so your code will look like this:
public events: BehaviorSubject<CalendarEvent[]> = new BehaviorSubject([]);
ngOnInit(): void {
this.getEvents();
}
public getEvents(): void {
this.apiService.getEvent()
.subscribe((data: any) => {
// do what you need or want with data
const mappedData = data.map((event: any) => {
event.start = new Date(event.start);
event.end = new Date(event.end);
return event;
});
this.events.next(mappedData);
},
(err:any) => console.error(err),
() => console.log('done loading events')
);
}
after this, simply subscribe to events
in the template
<div >
<ul *ngFor="let evnt of events | async">
<li>Title: {{evnt.title}}</li>
<li>Start: {{evnt.start}}</li>
<li>End: {{evnt.end}}</li>
<li>Creator: {{evnt.created_by}}</li>
</ul>
</div>
CodePudding user response:
I fixed the issues following: https://blog.angular-university.io/angular-2-rxjs-common-pitfalls/.