简体   繁体   English

如何将 Angular ngFor 与 Observable 一起使用

[英]How to use Angular ngFor with Observable

With Book class defined as: Book class 定义为:

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

I go ahead and create Observable object books$ :我提前 go 并创建Observable object 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);

Checking it with:检查它:

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

prints:印刷:

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

But using this observable with ngFor in the html template:但是在 html 模板中使用这个 observable 和ngFor

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

raises the ERROR :引发ERROR

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

How to solve this problem?如何解决这个问题呢? Here is the link to Stackblitz project:这是Stackblitz项目的链接:

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

Everything looks good except books$ represent a stream of objects, not arrays.一切看起来都不错,除了books$代表对象的 stream,而不是 arrays。 So might have to use keyvalue pipe.所以可能必须使用键值keyvalue Try the following尝试以下

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

Update: RxJS bufferCount operator更新:RxJS bufferCount运算符

The above solution however prints only the current notification.然而,上述解决方案仅打印当前通知。 If you wish to collect each notification and display them all, you could use RxJS bufferCount (or buffer if you don't exactly the amount of notifications) operator to collect all the notifications.如果您希望收集每个通知并将它们全部显示,您可以使用 RxJS bufferCount (或buffer ,如果您不完全了解通知的数量)运算符来收集所有通知。

Controller Controller

import { bufferCount } from 'rxjs/operators';  

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

Template模板

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

I've modified your Stackblitz我修改了你的Stackblitz

I would extract this behaviour into a new method:我会将这种行为提取到一个新方法中:

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

In the html:在 html 中:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM