0
votes

I have the following markup in my HTML. It works as supposed to and performs according to the expectations.

<ng-container *ngIf="stuff$ | async as data">
  <div *ngFor="let element of data">{{element.name}}</div>
</ng-container>

I started to tamper with it to see what I can brake/improve so, assuming that the as data only assigns a variable name to the resulting outcome of subscription (due to async pipe), I hoped that I can reuse data$ directly, without going about the extra variable. So I changed to this.

<ng-container *ngIf="stuff$ | async">
  <div *ngFor="let element of stuff$">{{element.name}}</div>
</ng-container>

This failed miserably, producing the error below.

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

While I understand the sense of the error, I don't see where it's coming from. The service that I subscribe to returns an observable of an array. Is the as'ing of the property being async'ed mandatory? I'm sure there's a subtle, little thing I missed when I was reading up on the asynchronous pipe but I'm failing to see it.

stuff$: Observable<Thing[]>;
ngOnInit() { ...
  this.stuff$ = this.stuffy.getStuff();
}
2
Why did you think that would work? You're effectively replacing a reference to the value returned by a function with a reference to its argument, they may not even be the same type.jonrsharpe
@jonrsharpe I can't motivate for this particular case. However, in my 20 years of playing with programming, I've been in a situation where I didn't think something would work, yet it did. Numerous times. In the weirdest ways imaginable (at least to me). So, although I didn't actually think it would work this time, the statistics told me that I might be wrong again. Does it make sense?Konrad Viltersten
To a certain extent, but in the absence of a reason to think it would work and given unambiguous feedback that it indeed does not, it's not clear to me why you were left with a question.jonrsharpe
@jonrsharpe I see where you're coming from. It's pure humbleness, I guess. There was a likelihood that the approach producing the error message actually was correct but hidden behind another, obscure error. It was a long shot but if you imagine that I'm not as bright as others, then it calls for not only establishing that it doesn't work but also for explaining why it doesn't work. And I was too ignorant to achieve that. Trust me, I wouldn't waste my time (nor others') if I was able to explain sufficiently reliably the intricate specifics of the observed phenomenon. :)Konrad Viltersten
@jonrsharpe I think one of the comments just proved my point. I simply was too dumb to figure out the following syntax myself: let item of stuff$ | async. But it was that approach I was trying to achieve (omitting the intermediate stuff declaration to pick item elements from). My apologies for being insufficiently eloquent.Konrad Viltersten

2 Answers

3
votes

That's simple: stuff$ contains an observavle. When you use the async pipe, behind the scenes angular subscribes to the observable and return it values to be used on the template.

When you use as data it will save the result of stuff$ | async to the data variable, allowing you to use it without needing to use the async pipe multiple times.

Your second code fails because you can't iterate over a Observable, since it's an object.

1
votes

you could just do this:

<div *ngFor="let element of stuff$ | async">{{element.name}}</div>

ngFor is designed for this.