You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular-Calendar自定义单元格模板异步加载事件失败排查

问题:angular-calendar异步加载事件无法显示,始终停留在加载状态

我正在开发一款使用angular-calendar生成日历的应用,用于展示酒店房间的每日价格。

组件代码(component.ts)如下:

events$!: Observable<CalendarEvent<{ hotel: Hotel }>[]>

ngOnInit(): void {
  this.fetchEvents()
}

fetchEvents(): void{
  this.hotelService.getHotels().pipe(
    map((hotels: Hotel[]) => {
      const events: CustomCalendarEvent[] = [];
      hotels.forEach(hotel => {
        if (hotel.rooms.single) {
          hotel.rooms.single.daily_prices.forEach(element => {
            events.push({
              start: new Date(element.start),
              price: element.price,
              title: '',
              allDay: true,
            })
          })
        }
      })
      return events
    })
  ).subscribe(events => {
    this.events$ = of(events)
    console.log(events)
  })
}

通过服务获取数据后,控制台输出显示数据正常,但HTML模板始终显示加载状态:

<ng-template #customCellTemplate let-day="day" let-locale="locale" class="cell">
    <div class="cal-cell-top">
        <span class="cal-day-number">
            {{ day.date | calendarDate:'monthViewDayNumber':locale }}
        </span>
    </div>
    <small class="price-cell">
        Precio habitación:
        <br>
        <strong>{{ day.events$ }}</strong>
    </small>
</ng-template>

<ng-template #loading>
    <div class="text-center">
      <i class="fas fa-spin fa-spinner fa-5x"></i> <br />
      Loading events...
    </div>
</ng-template>

<div *ngIf="events$ | async; else loading; let events">
    <div [ngSwitch]="view">
        <mwl-calendar-month-view
            *ngSwitchCase="'month'"
            [viewDate]="viewDate"
            [locale]="locale"
            [weekStartsOn]="weekStartsOn"
            [weekendDays]="weekendDays"
            [cellTemplate]="customCellTemplate"
            [events]="events">
        </mwl-calendar-month-view>
    </div>
</div>

参考angular-calendar官方文档示例实现,但仅能看到加载模板。尝试硬编码事件时,日历可正常显示数据,推测问题出在异步数据获取环节。请问为何异步加载的事件无法显示?我哪里操作有误?


问题分析与解决

你代码里有两个关键错误:

1. events$的赋值方式错误

你现在是在subscribe回调里把events$赋值为of(events),但组件初始化时async管道已经尝试订阅events$(此时它还未被赋值,是undefined),当你后续给events$赋值新的Observable时,async管道不会自动重新订阅,导致模板一直停留在加载状态。

正确的做法是直接把API请求的Observable赋值给events$,不需要手动subscribe:

events$!: Observable<CustomCalendarEvent[]>;

ngOnInit(): void {
  this.fetchEvents();
}

fetchEvents(): void {
  this.events$ = this.hotelService.getHotels().pipe(
    map((hotels: Hotel[]) => {
      const events: CustomCalendarEvent[] = [];
      hotels.forEach(hotel => {
        if (hotel.rooms.single) {
          hotel.rooms.single.daily_prices.forEach(element => {
            events.push({
              start: new Date(element.start),
              price: element.price,
              title: '',
              allDay: true,
            });
          });
        }
      });
      return events;
    })
  );
}

这样events$从一开始就是一个有效的Observable,async管道会自动订阅它,当API数据返回时自动更新模板。

2. 自定义单元格模板里的事件引用错误

angular-calendar的day对象里的events是同步数组,不是Observable,你写{{ day.events$ }}是错误的。需要遍历day.events数组,取出对应的价格值:

<ng-template #customCellTemplate let-day="day" let-locale="locale" class="cell">
    <div class="cal-cell-top">
        <span class="cal-day-number">
            {{ day.date | calendarDate:'monthViewDayNumber':locale }}
        </span>
    </div>
    <small class="price-cell" *ngIf="day.events.length > 0">
        Precio habitación:
        <br>
        <strong>{{ (day.events[0] as CustomCalendarEvent).price }}</strong>
    </small>
</ng-template>

这里假设每个日期对应一个价格事件,如果有多个,可以用*ngFor遍历显示。

修改这两处后,异步加载的事件就能正常显示在日历中了。


内容的提问来源于stack exchange,提问作者Alexander Romero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 15:33:15