Stevie Star
Stevie Star

Reputation: 2371

Angular 2 - Observables returning twice but after a few seconds...not sure why

I have an Ionic 2 app with a function that's aggregating a bunch of data via observables. The data comes back...except it's not always complete on the first return. After a few seconds, my data gets returned again, except both instances are now populated with the complete data. It's really weird and I'm not sure what's causing it.

Here is my function:

getUserStories(data) {
    return this._af.database
      .object(`/social/users/${data.id}`)

      // Switch to the joined observable
      .switchMap((user) => {

        let connections = [];
        let connectionKeys = Object.keys(user.connections);

        return Observable.combineLatest(
          connectionKeys.map((connectionKey) => this._af.database
            .object(`/social/users/${connectionKey}`)
          ),
          (...connections) => {

            connectionKeys.forEach((connectionKey, index) => {

              this._af.database
                .object(`/social/user_stories_seen/${connectionKey}/${data.id}`).subscribe(data => {

                // Iterate over the connections and append the correct "last_seen" variable
                connections.forEach((connection, index) => {
                  if(connection.$key === connectionKey) {
                    connections[index]['last_seen'] = data;
                  }

                })
              });
            })
            return connections;
          });
      })
   }

Here is the view that calls this functionality:

ionViewDidLoad() {

    // Get the user from storage and get all the connections
    this.storage.get('user').then(data => {

      //Get the user profile
      this._users.getUserStories({id: data.id}).subscribe(stories => {
        console.log('stories', stories);
      });
    })
}

Has anyone else run into this issue?

Upvotes: 1

Views: 670

Answers (1)

cartant
cartant

Reputation: 58410

The problem is that you have internal observables that are subscribing and then updating last_seen properties of the connections.

Those observables are not are not composed into the observable you are returning, so they can emit and update the connections after your combineLatest operator emits.

The implementation could be simplified by using a function that combines the connections and last-seen values:

getUserStories(data) {

  return this._af.database
    .object(`/social/users/${data.id}`)
    .switchMap((user) => {

      const getConnection = (connectionKey) => {
        return Observable.combineLatest(

          // Combine the connection and last-seen value:

          this._af.database
            .object(`/social/users/${connectionKey}`),
          this._af.database
            .object(`/social/user_stories_seen/${connectionKey}/${data.id}`),

          // Assign the last-seen value, but return the connection:

          (connection, seen) => {
            connection.last_seen = seen;
            return connection;
          }
        );
      };

      const connections = Object.keys(user.connections).map(getConnection);
      return Observable.combineLatest(...connections);
    });
}

Upvotes: 1

Related Questions