Apollo-angular: Loading state never emitted

Created on 9 May 2019  路  12Comments  路  Source: kamilkisiela/apollo-angular

Intended outcome:
When watchQuery is executed and data is not in cache, observable emits with loading flag set to true. This is important to show any kind of loading state in the view. This is the case in cache-and-network policy but not in others.

Actual outcome:
Observable emits only after data is loaded so loading flag is always false.

How to reproduce the issue:
Use watchQuery with strategy different then cache-and-network

Versions
Latest

Most helpful comment

Hi @kamilkisiela,

The comment of useInitialLoading says There's a big chance the next major version will enable that by default..
However, 2.0 was rolled out without it.
I think it should be removed and (re-?)integrated (*) as the only behaviour as I do not see why you would not want the first loading events.

Now, I'd like to put useInitialLoading on every watch query I make, but I can't set it via defaultOptions (type error + effectively not applied at runtime).
It would be really cool to be able to set it once and for all if the real fix is to be awaited for longer!

By the way, these are my current default options for watchQuery:

watchQuery: {
    fetchPolicy: 'cache-and-network',
    errorPolicy: 'all',
    notifyOnNetworkStatusChange: true
}

(*) I feel like the behaviour was different at some point in the past. I noticed that some of my UI I built around this feature seemed to not react the way it did before, basically I lost the "initial loading state" (basically, a spinner, and then a more discrete indicator for subsequent refreshes)... which led me here.

All 12 comments

I think we could fix it but it should be hidden under a flag to not break the current behavior. Anyone wants to implement it? I can guide and help, of course!

Glad this was pointed out as a bug. The current documentation definitely hints at it working the way @olaf89 is suggesting it should, and I have been wondering what I was doing wrong. I say "hints" because of this code snippet, that never sets an initial true value on this.loading:

import { Component, OnInit } from '@angular/core';
import { Apollo } from 'apollo-angular';
import gql from 'graphql-tag';

// We use the gql tag to parse our query string into a query document
const CurrentUserForProfile = gql`
  query CurrentUserForProfile {
    currentUser {
      login
      avatar_url
    }
  }
`;

@Component({ ... })
class ProfileComponent implements OnInit, OnDestroy {
  loading: boolean;
  currentUser: any;

  private querySubscription: Subscription;

  constructor(private apollo: Apollo) {}

  ngOnInit() {
    this.querySubscription = this.apollo.watchQuery<any>({
      query: CurrentUserForProfile
    })
      .valueChanges
      .subscribe(({ data, loading }) => {
        this.loading = loading;
        this.currentUser = data.currentUser;
      });
  }

  ngOnDestroy() {
    this.querySubscription.unsubscribe();
  }
}

This made me think loading would be set twice, true right away and false after completion.

See the documentation I'm referencing: https://www.apollographql.com/docs/angular/basics/queries/

@olaf89 @spencermefford @yashwp #1306 should enable that. Can't make it enabled by default, because it will break the current behavior.

That's great news @kamilkisiela! That should be perfect for my needs. I totally understand why it can't be enabled by default ATM.

Hi @kamilkisiela. Sorry for comment on closed issue, but it is strongly related. The case described by @olaf89 comes out also when _refetch_ method of QueryRef is triggered.

Even with useInitialLoading, the _valueChanges_ observable return result only once, when the actual response come ( I guess, that is why it's called "initial" :wink:) and the loading property is always false then. Is it currently possible to take advantage of _result.loading_ while refetching data? Problem does not occur with default fetch-policy for watchQuery.

I will be grateful for any suggestions.

Hitting the same issue, with refetch not firing a loading === true event.

Is there a workaround?

@qortex

A possible workaround would be to set the loading to true by calling pipe before subscribe, .valueChanges.pipe(o$ => { this.loading = true; return o$; }).

this.querySubscription = this.apollo.watchQuery<any>({
      query: CurrentUserForProfile
    })
      .valueChanges
      .pipe(o$ => { this.loading = true; return o$; })
      .subscribe(({ data, loading }) => {
        this.loading = loading;
        this.currentUser = data.currentUser;
      });

Thanks @stormwild
In that case, I guess you'd prefer to use tap operator, but I'm not sure it does what you want anyway. valueChanges will fire only when the value is known, so loading would never be true really.

What I do as a workaround is use startWith. As pseudo-code:

loading$ = value_changes_observable$.pipe(map(({data, loading}) => loading)), startWith(true));

Hi @kamilkisiela,

The comment of useInitialLoading says There's a big chance the next major version will enable that by default..
However, 2.0 was rolled out without it.
I think it should be removed and (re-?)integrated (*) as the only behaviour as I do not see why you would not want the first loading events.

Now, I'd like to put useInitialLoading on every watch query I make, but I can't set it via defaultOptions (type error + effectively not applied at runtime).
It would be really cool to be able to set it once and for all if the real fix is to be awaited for longer!

By the way, these are my current default options for watchQuery:

watchQuery: {
    fetchPolicy: 'cache-and-network',
    errorPolicy: 'all',
    notifyOnNetworkStatusChange: true
}

(*) I feel like the behaviour was different at some point in the past. I noticed that some of my UI I built around this feature seemed to not react the way it did before, basically I lost the "initial loading state" (basically, a spinner, and then a more discrete indicator for subsequent refreshes)... which led me here.

useInitialLoading should almost certainly be the default behaviour...

@kamilkisiela, what about fetch? I'm not able to get a loading: true on my fetch's at the moment and I'm scratching my head

Was this page helpful?
0 / 5 - 0 ratings

Related issues

chihab picture chihab  路  4Comments

TobiasKrogh picture TobiasKrogh  路  4Comments

GlauberF picture GlauberF  路  6Comments

simonhaenisch picture simonhaenisch  路  3Comments

miquelferrerllompart picture miquelferrerllompart  路  7Comments