Angular 6 * ngFor возвращает пустой массив, а массив фактически заполнен - PullRequest
0 голосов
/ 13 ноября 2018

В настоящее время я разрабатываю простой чат (например, 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'), проблема больше не будет отображаться, но, когда я отправлю новое сообщение, у меня будет новое сообщение, вызываемое несколько раз в представлении (не в базе данных).

Ответы [ 2 ]

0 голосов
/ 13 ноября 2018

Вы получаете данные от службы, поэтому может потребоваться использование асинхронного канала.

<li *ngFor="let message of msgService.messageList | async">
    <p class="message">{{message.msg}}</p>
</li>
0 голосов
/ 13 ноября 2018

Обновите ваш 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, который теперь будет иметь данные для перебора и отображения в вашем списке.

...