Closed ribizli closed 7 years ago
My current workaround for this is to delay the emission into the next event loop (???):
this._gameService.gameChanges$.delay(0).subscribe(g => console.log(`game changed: ${g.id}`));
apollo.subsribe
is wraped with zone current zone , so change detection should be invoked.
can you show the components code? do you use ON_PUSH?
No ON_PUSH at all. My other comp uses watchQuery with async. I expect it's view to get updated automatically but it won't. More code sample I can provide later on... UPDATE: added code
// game service
@Injectable()
export class GameService {
gameChanges$: Observable<Game>;
constructor(private _apollo: Apollo) {
this.gameChanges$ = _apollo.subscribe({
query: gameChanges
}).map((r: { gameChanged: Game }) => r.gameChanged);
}
game(id: number) {
return this._apollo.watchQuery<GameResult>({
query: gameQuery,
variables: { id }
}).map(r => r.data && r.data.game);
}
}
// game component
@Component({
template: `
<pre *ngIf="game$ | async as game">
{{game | json}}
</pre>
`
})
export class GameComponent {
game$: Observable<Game>;
constructor(private _gameService: GameService, _route: ActivatedRoute) {
const id$ = _route.params.map(p => +p['id']);
this.game$ = id$.switchMap(id => _gameService.game(id));
}
}
In the OP I've also shown the parent component (it's routing child is the game component) with the subscription. From the observables I get all the emitted data correct, I also checked the Apollo Client's cache, everything is updated but the view. After the next CD, the view is also updated. And the mentioned workaround is also working (don't know why).
I am also seeing this issue on our project. Delay didn't work for me, instead Apollo subscription results seem to have to be wrapped in a zone.run(() => { ... }) to get Angular templates to update.
We are using stock change detection (i.e NO ON_PUSH) Could this also be related to #295?
I can again confirm, that this bug is still valid.
I've tested it with NgZone.isInAngularZone()
in the next()
handler, and any emission caused by an Apollo Client cache update is outside of NgZone
.
Again a short description:
I use watchQuery
to query an object. The first result is emitted in NgZone
. Later a GraphQL Subscription sends an update of this object. The emission from the subscription's Observable
is also correctly in NgZone
. But the caused cache update in the client's cache triggers an emission of the watchQuery
which is not in NgZone
anymore.
My workaround is really to delay(0)
the subscription emission, which I assume starts a change detection right after the cache update emission already happened.
Workaround No.2 - wrapping the watchQuery observable into NgZone
:
function observeOnZone<T>(this: Observable<T>, zone: NgZone): Observable<T> {
return Observable.create(observer => {
const onNext = (value) => zone.run(() => observer.next(value));
const onError = (e) => zone.run(() => observer.error(e));
const onComplete = () => zone.run(() => observer.complete());
return this.subscribe(onNext, onError, onComplete);
});
};
Observable.prototype.observeOnZone = observeOnZone;
declare module 'rxjs/Observable' {
interface Observable<T> {
observeOnZone: typeof observeOnZone;
}
}
// in service
this._apollo.watchQuery<CurrentPlaylistQueryResult>({
query: currentPlaylistQuery
}).map(r => r.data.currentPlaylist)
.observeOnZone(this._ngZone);
works in apollo-angular@1.0.0
If a subscription event comes, the store is updated, the observable emits, but no change detection is running in angular. (I need to interact with a component to get the view being updated)