1

New to Angular/Apollo/TS and this is driving me nuts, so any help is appreciated.

I am working on setting up a small app with Angular 10, Apollo, and a GraphQL API. I recently built the same thing in Vue and thought recreating the project would be a good way to pick up some Angular.

My connection to the API is working, as is my query, but I can't figure out how to map the results to an array so I can access them in my component. Using console.log inside the subscription shows the correct data is returned. console.log outside of the query on 'this' shows the query results, however they are never saved/mapped to the variable they should be set to.

Here's the code for my service:

import { Injectable } from '@angular/core';

import { Apollo } from 'apollo-angular';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

import gql from 'graphql-tag';

const USER_SEARCH = gql`
  query getUsers {
    search(query: "moose", type: USER, first: 10) {
       nodes {
         ... on User {
           login
           email
           location
           name
         }
       }
       pageInfo {
         hasNextPage
         hasPreviousPage
         startCursor
         endCursor
       }
       userCount
     }
  }`;

export class UserService {
  loading: boolean = true;
  users: [];

  constructor(private apollo: Apollo) { }

  getUsers(): any {
    this.apollo.watchQuery<any>({
      query: USER_SEARCH
    })
      .valueChanges
        .subscribe(({ data, loading }) => {
         this.loading = loading;
         this.users = data.search;
        });
        console.log(this);

    return this.users;
  }
}

I can call the getUsers() function from my component, and 'this' has the service listed, and inside of it 'users' has my query results listed in it. However, console.log for this.users in the service or the component returns undefined.

I've tried about every type of example I could find, including the query examples from the apollo docs, and the example of using apollo with angular from hasura.io. Tried using a pipe and map, pluck, just valueChanges, a few different subscribes, setting a variable inside the function to assign the data value to, setting the query to variable, setting the query in ngOnInit in the component, and a few other things I'm sure I'm forgetting. Nothing seems to work. I looked into using a callback to wait for the query to return before setting the value, but my understanding is that I shouldn't have to do anything like that. I'm sure it's something dumb I'm missing or don't know about with Apollo or Angular, but I'm just not positive what it is I'm missing.

Any ideas?

mooseshark
  • 15
  • 3

3 Answers3

0
this.getUsers = this.getUsers.bind(this);

within a constructor?

olkivan
  • 89
  • 1
  • 3
  • Thanks for the suggestion! This isn't working directly out the box, but binding scope gives me something new to work off of at least. Appreciate it! – mooseshark Sep 07 '20 at 20:00
-1

using setTimeout is not an ideal solution, you can directly update your component variable in subscribe callback function and do whatever you want to do with it in your template. Look at my example

getItems() {
    this.apollo
      .watchQuery({
        query: this.getItemsQuery,
      })
      .valueChanges.subscribe((result: any) => {
        this.items = result?.data?.items;
      });
  }

and in template

<mat-option *ngFor="let item of items" [value]="item.price">
    {{ item.name }}
</mat-option>
            
 
     
            
Muhammad Awais
  • 1,608
  • 1
  • 21
  • 21
-2

Maybe not the ideal solution, so I'm still open to trying other things, but I was able to get the value set in my component by using a promise with a timer in the service, then an async await in the component.

Service

  getUsers(): any {
    return  new Promise((resolve, reject) => {
      let me = this;
      this.apollo.watchQuery<any>({
        query: USER_SEARCH
      })
        .valueChanges
          .subscribe(({ data, loading }) => {
           this.loading = loading;
           this.users = data.search;
         });

      setTimeout( function() {
        if(me.users !== 'undefined'){
          resolve(me.users)
        }
      }, 1000)
    })
  }

Component

  async getUsers(): Promise<any> {
      this.users = await this.userService.getUsers();
      console.log(this.users);
  }

This allows this.users to be set from the service. As far as I can tell, Apollo is still running the query when Angular starts setting values, resulting in the value originally being shown as undefined, but my service having values from the query in the console. Not sure if there's a better way with Apollo or Angular to resolve this issue, but if so I'd love to hear about it.

Thanks!

mooseshark
  • 15
  • 3