如何在 Observable 中使用 Angular ngFor

How to use Angular ngFor with Observable

Book class 定义为:

class Book {
   id: number;
   name: string;
   constructor(id: number, name: string) { 
     this.id = id;
     this.name = name;
  }
}

我继续创建 Observable 对象 books$:

const book1: Book = new Book(1, "Title 1");
const book2: Book = new Book(2, "Title 2");
function booklist(observer) {
  observer.next(book1);
  observer.next(book2);
  observer.complete();
  return {unsubscribe() {}};
}
this.books$ = new Observable(booklist);

正在检查:

this.books$.subscribe(each => console.log(each));

打印:

Book {id: 1, name: "Title 1"}
Book {id: 2, name: "Title 2"} 

但是在 html 模板中将此 observable 与 ngFor 一起使用:

<ul>
  <li *ngFor="let book of books$ | async" >
    Id: {{book.id}}, Name: {{book.name}}
  </li>
</ul>

提高 ERROR:

   Error: Cannot find a differ supporting object '[object Object]' of type 'Title 2'. NgFor only supports binding to Iterables such as Arrays.

如何解决这个问题?这是 link 到 Stackblitz 项目:

https://stackblitz.com/edit/angular-ivy-isebs7?file=src%2Fapp%2Fapp.component.ts

一切看起来都不错,除了 books$ 表示对象流,而不是数组。所以可能必须使用 keyvalue 管道。尝试以下

<ul>
  <ng-container *ngIf="(books$ | async) as books">
    <li *ngFor="let book of books | keyvalue" >
      {{book.key}}: {{book.value}}
    </li>
  </ng-container>
</ul>

更新:RxJS bufferCount 运算符

然而,上述解决方案仅打印当前通知。如果你想收集每个通知并显示它们,你可以使用 RxJS bufferCount (or buffer 如果你不准确的通知数量)运算符收集所有通知。

控制器

import { bufferCount } from 'rxjs/operators';  

ngOnInit(): void {
  ...
  this.books$ = <Observable<Book[]>>(new Observable(booklist).pipe(bufferCount(2)));
  this.books$.subscribe(each => console.log(each));
}

模板

<ul>
  <ng-container *ngFor="let books of books$ | async">
    <li *ngFor="let book of books | keyvalue" >
      {{book.key}}: {{book.value}}
    </li>
  </ng-container>
</ul>

我修改了你的Stackblitz

我会将此行为提取到一个新方法中:

getBooksArr$: Observable<Book[]> {
   return this.books$.pipe(map((book) => Object.values(book)));
}

在html中:

<ul>
  <li *ngFor="let book of getBooksArr$() | async" >
    Id: {{book.id}}, Name: {{book.name}}
  </li>
</ul>