angular / angular

Deliver web apps with confidence 🚀
https://angular.dev
MIT License
96.05k stars 25.41k forks source link

Support for AsyncIterable within AsyncPipe #44558

Open vitaly-t opened 2 years ago

vitaly-t commented 2 years ago

Note from the Angular team: we're treating this issue as a feature request for AsyncIterable support in AsyncPipe.

Description

Angular can render native Iterable within its ngFor directive, but not AsyncIterable, complaining when we add | async filter to such a type.

Proposed solution

AsyncIterable should be supported with | async filter, the same as for any Observable.

Alternatives considered

Wrapping native AsyncIterable into RXJS observable just to make it usable within HTML-rendering engine - isn't great, and it creates an unnecessary overhead for a native type, which adds a subscription logic (AsyncIterable is simpler, and it doesn't need any subscription logic)


Afterthought: It should work not just with ngFor, but everywhere where | async filter is applicable.

angular-robot[bot] commented 2 years ago

This feature request is now candidate for our backlog! In the next phase, the community has 60 days to upvote. If the request receives more than 20 upvotes, we'll move it to our consideration list.

You can find more details about the feature request process in our documentation.

alxhub commented 2 years ago

I think the comparison between Observable and AsyncIterator is misleading here. NgFor requires a synchronous array for rendering, even if that array is produced asynchronously. That is, in the invocation*ngFor="let item of items$ | async", items$ must be an Observable of some iterable type, like an Item[] array. It's not possible to use NgFor with the async pipe to iterate over an Observable<Item> if Item itself is not iterable.

It might be possible for Angular to support using AsyncIterable with the async pipe instead of Observable, but NgFor will always require a synchronous iterable value.

I'm going to change the title of this issue to cover supporting AsyncIterable in AsyncPipe, which I think is the real feature request here.

angular-robot[bot] commented 2 years ago

Just a heads up that we kicked off a community voting process for your feature request. There are 20 days until the voting process ends.

Find more details about Angular's feature request process in our documentation.

angular-robot[bot] commented 2 years ago

Thank you for submitting your feature request! Looks like during the polling process it didn't collect a sufficient number of votes to move to the next stage.

We want to keep Angular rich and ergonomic and at the same time be mindful about its scope and learning journey. If you think your request could live outside Angular's scope, we'd encourage you to collaborate with the community on publishing it as an open source package.

You can find more details about the feature request process in our documentation.

vitaly-t commented 1 year ago

I think the comparison between Observable and AsyncIterator is misleading here

I think a lot of you wrote there is misleading. It was asked from start, about AsyncIterable, and not AsyncIterator.

I honestly do not understand how there can be any kind of complexity. For anything that already supports Observable, it should be trivial to add support for AsyncIterable.

In my projects, I am using iter-ops everywhere, because I want the best performance, and I do not want synthetic primitive types likes Observable, working with native Iterable everywhere, except inside angular views, because they do not naturally support iterable. In this day and age, I find it quite odd, in fairness.

vitaly-t commented 1 year ago

Here's a very simplified example of the type of workarounds that I have to resort to...

The component below updates a list of numbers once a second:

import {Component, OnInit} from '@angular/core';
import {pipeAsync, delay} from 'iter-ops';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

  source: AsyncIterable<number>;

  public data: number[] = [];

  constructor() {
    this.source = pipeAsync([1, 2, 3, 4, 5], delay(1000));
  }

  async ngOnInit() {
    for await(const i of this.source) {
      this.data.push(i);
    }
  }
}

And then the view that consumes it:

<div *ngFor="let item of data">
  <h1>{{item}}</h1>
</div>

So I have to keep an extra variable for the view data + loop through the source to update the view data.

If we had support for AsyncIterable in Angular, I could just use source | async inside the view.