首页 > 解决方案 > 在视图渲染之前设置一个 Array[]

问题描述

目前,我正在尝试找出一种events: CalendarEvent[] = []; 在视图呈现之前填充此数组的方法。当我试图从我拥有的一些数据库条目中填充日历时,但我已经在一个函数中提取了数据,然后我在另一个函数中分配。问题是我似乎无法在渲染之前更新数组,但可以通过按钮单击事件后记轻松更新它。

所以我潜入了不同的方法来解决这个问题,我尝试了设置加载器而不是在函数完成之前使用 ngIf 渲染,但是当涉及到很多角度时,这对我来说仍然是一个错过,所以我不确定是什么在这方面有可能的方法。

据我了解,目前我的服务返回条目的方式它只返回一个承诺而不是值,因此视图没有数据,所以我知道我有办法操纵组件状态,但是有没有办法无需在渲染后刷新组件即可实现此目的

我认为这样的事情会起作用,但据我了解,Angular 中的异步与 c#/Xamarin 等中的不同

async ngOnInit(){
    await this.getEntries();
    await this.setCalendar();
  }

我获取条目:

  getEntries(){
    this.entryservice.getAventry().subscribe(data => {
      this.entries = data.map(e => {
        return {
          id: e.payload.doc.id,
          ...e.payload.doc.data() as {}
        } as Entrymodel;
      })
    });
    console.log("Get Done");
  }

然后我将它们推送到日历数组:

 setCalendar(){
     this.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,
        },
      ];
    
    });

日历库 StackBlitz 或多或少相同的东西 StackBlitz

请注意: Entires Array 是我从数据库中获取数据的地方,问题是events: CalenderEvent[] = [];在视图渲染之前没有被填充所以日历是空的并且当前填充它的唯一方法是使用点击事件或类似的东西在初始渲染后排序,我尝试了以下答案,它们对我不起作用

一个我似乎忘记添加的小注释:

我使用的变量:

  entries: Entrymodel[] = [];
 events: CalendarEvent[] = [];

入口模型:

export class Entrymodel {
    id: string;
    surname: string;
    color: string;
    startDate: Startdate;
    endDate: Enddate;
    info: string;
    status?: string;
    inbet?: Inbetween[];
    editing?: boolean;
}

export class Startdate{
    day: string;
    month: string;
    year: string;
}

export class Enddate{
    day: string;
    month: string;
    year: string;
}

export class Inbetween{
    day: string;
    month: string;
    year: string;
}

我正在尝试获取条目,因为它们包含需要被推入事件数组以显示在日历上的日期

标签: angulartypescriptfirebase-realtime-database

解决方案


当智能组件和哑组件有用时,将此问题视为一个很好的示例。

正如您自己编写的那样 - 管理状态在这里很重要,如果您将组件分成两个 - 智能组件和哑组件,它非常容易。

智能组件将准备所有数据,而哑组件将呈现它。

例子

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>

哑组件.ts:

@Input('entries') entries: any[];
@Input('loading'): boolean;

哑.component.html:

<div *ngIf="!loading; else loading"> ... </div>

<ng-template #loading>
  // spinner
</ng-template>

ps 这里为了简单起见,我将状态存储在一个智能组件中(虽然我们通常为此使用存储)并且方法通常只是一个示例,因为它的整个架构应该确定数据如何来回流动。

编辑

我刚刚注意到您正在使用实时数据库,对吗?(可能是 Firebase - 会在您的帖子中添加一个标签。如果不是 Firebase,请更改它)。这改变了这个概念。对于像 SQL 这样的普通数据库,当您进行 HTTP 调用时,它会返回一次- 响应或错误。使用实时数据库时,您会得到一个流,例如 Web 套接字。这意味着您必须将其视为流,因为它可以在将来的任何时间返回您的值。

所以你问什么 - 你需要根据entries流媒体的结果来获取事件。并且该流可以随时推送值。所以你可以做什么 - 映射entriesevents

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,
        },
      ];
    
    });

setCalendar 函数的更改 -entries.forEach更改 为entries.mapthis.events = [ ...this.events, return

smart.component.html:

<app-dumb-component
  [events]="events | async"
  [loading]="loading"
></app-dumb-component>

现在在这一点上,loading属性将仅对第一个连接有用,因为稍后它将立即发出。


推荐阅读