angular: AsyncPipe doesn't work with RxJs Subject
I’m submitting a … (check one with “x”)
[X] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
Current behavior AsyncPipe works properly with BehaviorSubject, but it don’t work with Rx Subject. More info: http://stackoverflow.com/questions/39902413/angular-2-0-1-asyncpipe-doesnt-work-with-rx-subject
Expected behavior Works with Subject
Minimal reproduction of the problem with instructions
export class AppComponent {
foo = new Subject<Array<number>>();
constructor(){
setTimeout(() => {
this.foo.next([1,2,3]);
}, 3000);
}
getFoo(){
return this.foo.asObservable();
}
}
<span *ngFor="let e of foo.asObservable() | async">{{e}}</span>
What is the motivation / use case for changing the behavior? I use Subject because I somethines need subscribe to the service when data is loaded an make decisions. BehaviorSubject forces me to initialize the object with an empty data.
Please tell us about your environment: Not required
- Angular version: 2.0.X Angular 2.0.1
- Browser: All
- Language: all
- Node (for AoT issues):
4.4.4
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Reactions: 6
- Comments: 16 (9 by maintainers)
Closing because we won’t document such a narrow use case in the general Angular docs. This would be better as a Stack Overflow Q&A
The problem here is calling a method from your template - this means every time change detection runs, you’re calling your getFoo() function, which returns a new instance of the observable, which resets the async pipe.
As @DzmitryShylovich’s example shows, its generally preferable to bind to properties on your component:
In my project. I had a service with a collection wrapped by BehaviorSubject. To retrieve the collection out of the service I used the following method
getData(): Observable { return this._data.asObservable() }
. Then I inject the service into components as a component variable and used the method getData() directly in the ngFor. At this point everything worked properly.The problem came out when I changed the word BehaviorSubject for Subject and the code failed. I tried to subscribe to service in the component
this._service.getData().subscribe(data => console.log(data))
and I could check the data was arriving to this point. So I concluded it was a async pipe problem.@robwormald The weird behavior is that all of this don’t happen with BehaviorSubject, maybe cause it’s initialized at the beginning.
@DzmitryShylovich Try removing the setTimeout, it wont work anymore.
Something along the lines of
next
ing on the subject while it has not been subscribed to yet causes this bug. It gets subscribed to when the view is initialized, therefore I think the moment the view is initialized is related.See this example for a test of all the possible ways I could think of someone would use the async pipe in combination rxjs.
So I still do not understand. I too have an
async
pipe which works withBehaviorSubject
but not withSubject
. What should I do? Just convert to aBehaviorSubject
? Is usingngAfterViewInit
a good approach?@realappie I can confirm this behavior. Took me almost all day to realize this wasn’t a bug in my own approach.
service.ts
component.ts
component.html
@briancodes months after, I admit it’s reasonable to say knowledge of the various
Subject
s implementations is needed to understand the use-cases and the effects produced of each one. I did not have a sufficient understanding back then.@lppedd If a
Subject
emits a value withnext
, anasync
pipe will only handle this event if its already subscribed to the Subject. What happens in the Angular template is that the async pipe subscription can occur afternext
has been invoked. Subscribing late to the Subject means it misses the previous eventWith a
BehaviourSubject
orReplaySubject
, a late subscription still receives the previous event. That’s why they work more consistently withasync
pipeCan’t reproduce http://plnkr.co/edit/YPEwCM9fmohq5i4yBtm1?p=preview