【问题标题】:Angular2: *ngFor, AsyncPipe, and indexAngular2:*ngFor、AsyncPipe 和索引
【发布时间】:2016-10-25 09:40:59
【问题描述】:

在上一个问题 here 中,我试图仅在 2 条消息之间发生更改时才显示日期。

不同之处在于我现在连接到一个实时数据库 (Firebase),所以我订阅了数据源并在通过索引和 *ngIf 之前通过异步管道传递它:

<div *ngFor='let message of (chat | async) ; let i = index'>
    <button *ngIf="i == 0 || (message.timestamp | date: 'ddMMMMyyyy') != ((chat | async)[i-1].timestamp | date: 'ddMMMMyyyy')">
        {{ message.timestamp | date:'ddMMM' }}
    </button>
    ...
    <!--More html elements below (omitted)-->
    ...
</div>

这在我第一次加载视图时效果很好,但是,如果我将新条目推送到 chat,我会收到以下错误:

TypeError: Cannot read property '0' of null

也许我不太确定异步管道是如何工作的,但是当我尝试返回 {{ (chat | async).length }} 时,它会按预期工作。有关解决方法/正确做法的任何建议?

【问题讨论】:

  • 你检查||在模板中使用时是否短路?可能是一个错误。
  • @GünterZöchbauer 短路的目的是因为在索引 0 处的消息之前没有任何内容,因此它应该返回 true。在索引 1 上,[i-1] 的计算结果为 0,这就是引发异常的地方。
  • 我知道这是故意的,但我怀疑它是否真的发生了。
  • @GünterZöchbauer 是的!我可能会在 OP 中发布一张图片,但显示带有日期“按钮”的第一个消息气泡,之后没有任何内容。

标签: javascript angular firebase firebase-realtime-database ionic2


【解决方案1】:

如果你想同时使用 *ngFor、AsyncPipe 和 index - 你应该使用这个结构:

  <ul>
      <li *ngFor="let person of obsPersons | async as persons; index as i">
           {{i + 1}} out of {{persons.length}}: {{person.personId}}  
       </li>
  </ul> 

在 Angular 7 上测试并运行。

【讨论】:

    【解决方案2】:

    正如上面@Primal Zed let company of (filteredCompaniesAliases | async); let i = index" 所提到的,应该使用纯 html 表的语法示例:

    <table>
       <tr *ngFor="let company of (filteredCompaniesAliases | async); let i = index"">
                    <td>
                        {{selectedDiscountableCharge.name}}
                    </td>
                    <td>
                        ${{selectedDiscountableCharge.amount}}
                    </td>
                    <td>
                        ${{selectedDiscountableCharge.amount - ( (selectedDiscountableChargePercentanges / 100) * selectedDiscountableCharge.amount ) }}
                    </td>
        </tr>
    </table>
    

    在您的组件中:

    companyAliasFilterCtrl: FormControl;
    filteredCompaniesAliases: Observable<any[]>;
    
    ...
    
    this.filteredCompaniesAliases = this.companyAliasFilterCtrl.valueChanges
    .pipe(
      startWith(''),
      map(company => company ? this.filterOperatorsAliases(company) : this.companies.slice())
    );
    

    【讨论】:

      【解决方案3】:

      我使用一个函数来显示(或不显示)日期。因此,仅在更改时才显示日期(在此示例中):

      <ion-list no-lines>
      <ion-item-sliding *ngFor="let trip of tripsExt$ | async; let i = index">
        <ion-item>
          <ion-row (click)="change(trip)">
            <ion-col col-6>
              {{showOnChange(trip.date)}}
            </ion-col>
            <ion-col col-6>
              {{trip.end_address_name}}
            </ion-col>
          </ion-row>
        </ion-item>
        <ion-item-options side="left">
          <button ion-button color="primary" (click)="delete(trip)">
            Delete
          </button>
        </ion-item-options>
      </ion-item-sliding>
      </ion-list>
      

      使用 showOnChange:

        showOnChange(currentDate) {
          if (currentDate != this.previousDate) {
            this.previousDate = currentDate
            return currentDate
          }
          return ''
        }
      

      【讨论】:

        【解决方案4】:

        如果其他人发现它,因为它是带有关键字的第一个结果,我可以使用这样的异步管道获取 *ngFor 的索引(假设 messages 是可迭代的 Observable):

        <div *ngFor="let message of (messages | async); let i = index;">
        

        【讨论】:

          【解决方案5】:

          仍然不确定如何在这里操作 AsyncPipe,但我确实找到了一种不使用管道的解决方法。希望在将其标记为关闭之前,我会等待更好的答案。

          我订阅了班级中的数据源,并在显示之前使用 for 循环操作数组。

          我的问题中的(模板)代码现在变成了:

          <div *ngFor='let message of messages; let i = index'>
              <button *ngIf="message.isNewDay">
                {{ message.timestamp | date:'ddMMM' }}
              </button>
              ...
              <!--More html elements below (omitted)-->
              ...
          </div>
          

          在控制器中:

          private chatid: string //chat id passed from previous screen
          private chat: FirebaseListObservable<any>;
          private messages: any = [];
          
          constructor(private firebase: FirebaseService,
                      private _datepipe: DatePipe) {
          }
          
          ionViewLoaded() {
              this.chat = this.firebase.database.list('/chat-messages/' + this.chatid);
              this.chat.subscribe((data) => {
                  this.messages = data;
                  for (let i: number = 0; i < this.messages.length; i++) {
                      if (i === 0)
                              this.messages[i].isNewDay = true;
                      else {
                          let date1 = this._datepipe.transform(this.messages[i].timestamp, 'ddMMMMyyyy');
                          let date2 = this._datepipe.transform(this.messages[i-1].timestamp, 'ddMMMMyyyy');
                          if (date1 !== date2)
                              this.messages[i].isNewDay = true;
                          else
                              this.messages[i].isNewDay = false;
                      }
                  }
              });
          }
          

          请注意,我目前在类代码(以及模板中)中使用 DatePipe,因此必须使用 providers: [DatePipe]pipes: [DatePipe]

          【讨论】:

            猜你喜欢
            • 2017-08-22
            • 2016-05-26
            • 2017-01-09
            • 2018-09-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-05-22
            • 2017-04-25
            相关资源
            最近更新 更多