【问题标题】:Angular 6 *ngFor returns empty array while array it's actually fullAngular 6 *ngFor 返回空数组,而数组实际上已满
【发布时间】:2019-04-15 17:22:46
【问题描述】:

我目前正在为 Web 应用程序开发一个简单的聊天(如 Facebook)。 我使用 Angular 6 作为框架,使用 Firebase 作为我的数据库。

当用户点击某个对话时,我会使用 .on("child_added, //function here) 检索以前的消息,然后将结果推送到将使用 *ngFor 循环显示的数组中。

我遇到的奇怪问题是消息有时会正确显示,有时根本不显示。发生这种情况时,只要我单击任意位置,*ngFor 就会再次被调用,一切看起来都很好。

使用console.logs我发现数据每次都被正确推送到数组中,但是由于某种原因,ngFor(与ngAfterViewChecked相同)有时会更新,有时只会返回一个空数组.

我的 .ts 文件(相关部分):

ngAfterViewChecked() {
  /*
    when everything works, this will be called everytime something changes
    (even after the array gets populated) 
    when the issue comes up, this will be called as usual but it won't be called after the array gets populated,
    thus returning an empty array the last time it was called 
  */

  console.log(this.msgService.messageList)
} 

//this will be called everytime a user clicks on a conversation on the left sidebar
getSpecConversation(conversation) {
  //emptying the array 
  this.msgService.messageList = [];

  //calling the .off using previous conversation key
  this.msgService.getConversation(this.msgService.selectedConversation.$key)
    .off('child_added');

  //getting messages of currently selected conversation
  this.msgService.getConversation(conversation.$key)
    .on('child_added', (data => {
      //push the data into array
      this.msgService.messageList.push(data.val());
    })
  );

  //storing currently selected conversation
  this.msgService.selectedConversation = conversation;
}

模板(相关部分):

<ul class="conversation-list">
  <li *ngFor="let message of msgService.messageList" class="conversation-item" [class.sender]="message.byUid == userInfoService.userUid">
    <p class="message">{{message.msg}}</p>
    <p class="msg-time">
    <span>{{message.time | date: 'shortTime'}}</span></p>
  </li>
</ul>       

服务:

getConversation(sid: string) {
  return this.database.ref('/messages')      
}

感谢您的帮助

更新 如果有帮助,如果我删除 .off('child_added') 方法,问题将不再出现,但是,当我发送新消息时,我会在视图中多次调用新消息(而不是在数据库中)。

【问题讨论】:

    标签: firebase angular6 ngfor


    【解决方案1】:

    更新您的template 并在显示之前检查数组是否包含数据。

    <ul class="conversation-list" *ngIf="msgService.messageList && msgService.messageList.length > 0">
      <li *ngFor="let message of msgService.messageList" class="conversation-item" [class.sender]="message.byUid == userInfoService.userUid">
        <p class="message">{{message.msg}}</p>
        <p class="msg-time">
        <span>{{message.time | date: 'shortTime'}}</span></p>
      </li>
    </ul>   
    

    这可能是一个竞争条件 - ngFor 循环可以在数组中包含任何数据之前运行,然后当您单击页面时,一个挂钩正在运行,告诉 ngFor 再次运行 - 这次查找数据。

    当您运行 ngIf 之前它会检查数据时,一旦它可用,它就会允许 ngFor 运行,现在将有数据迭代并显示在您的列表中。

    【讨论】:

    • 感谢您的回答。我按照建议更新了模板,但问题仍然相同。我注意到当我选择一个对话时发生错误,然后选择另一个对话,然后再次选择第一个对话。尽管情况并非总是如此,但似乎大多数时候都是如此。再次感谢
    • 所以,理论上,你的答案似乎是正确的。如果我添加一个虚拟&lt;p *ngIf="!msgService.messageList || msgService.messageList.length === 0"&gt;nothing here&lt;/p&gt;,这将在对话更改之间的很短的时间内可见。当问题发生时,会不断地看到“这里什么都没有”。再一次,只有当我做某事时,它才会显示消息列表
    • 这很奇怪 - 如果您在生产环境中构建您的应用程序 ng b --prod 并运行它是否有效?是否存在生命周期挂钩未正确触发的错误?
    【解决方案2】:

    您正在从服务获取数据,因此您可能需要使用异步管道。

    <li *ngFor="let message of msgService.messageList | async">
        <p class="message">{{message.msg}}</p>
    </li>
    

    【讨论】:

    • 消息列表不是可观察的/承诺它是一个静态数组,所以这不起作用。
    • @sketchthat 是的,你是对的。我总是使用这样的东西来防止这种类型的错误。 *ngIf="msgService.messageList?.length &gt; 0 &amp;&amp; !isLoading"isLoading 会根据状态而改变。
    • @ams 感谢您的回答。正如sketchthat 正确所说,messageList 是一个静态数组。无论如何,我尝试了类似于您在上面评论中所说的内容,使用 isLoading 来控制进度微调器。当用户点击对话时,isLoading 将变为真,因此只显示微调器。在我将结果推送到数组的代码部分下方,我将 isLoading 设置为 false 以隐藏微调器并显示结果。同样的行为,有时会很好地工作,并会发出其他问题。
    猜你喜欢
    • 2021-10-25
    • 2020-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-03
    • 2019-02-25
    • 2019-02-07
    • 2020-01-14
    相关资源
    最近更新 更多