Angular Resolver -resolving data from HTTP call is not working

1.1k views Asked by At

I'm trying to resolve data from HTTP call from graphql apollo client. The data does not get resolved and the component using the resolver cannot access the data.

In the logs , I can see that the observable is returned first and then data from service is returned.

The data from service - {name: "s raina", id: "e78903e0-5214-11e8-93f9-8951cc65e163", country: "sa", __typename: "Cricketer", Symbol(id): "Cricketer:e78903e0-5214-11e8-93f9-8951cc65e163"}

In resolver, instead of returning an observable, I tried returning subscribing to the observable and returning the data. In this case, the component using resolver accesses undefined data after which the service gets the data.

Any help would be appreciated.

Resolver:

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

import { Resolve } from '@angular/router';
import { Observable } from 'rxjs';
import { Cricketer } from './types';
import { CricketerService } from './cricketer.service';
import { ActivatedRouteSnapshot } from '@angular/router/src/router_state';
@Injectable()
export class CricketerResolver implements Resolve<any> {
  cricketer: any;
  constructor(private cricketerService: CricketerService) {

  }

  resolve(route: ActivatedRouteSnapshot) {
    console.log(this.cricketerService.getCricketer(route.paramMap.get('id')));
    return this.cricketerService.getCricketer(route.paramMap.get('id'));
  }
}

Service:

import { Injectable } from '@angular/core';
import { Apollo } from 'apollo-angular';
import gql from 'graphql-tag';
import { map , filter } from 'rxjs/operators';

import { Query , Cricketer } from './types';
import { BehaviorSubject } from 'rxjs';
@Injectable()
export class CricketerService {
  constructor(private apollo: Apollo) {}
  private searchInput: BehaviorSubject<String> = new BehaviorSubject<String>('');

  getAllCricketers(searchTerm: String) {
    return this.apollo.watchQuery<Query>({
        pollInterval: 10000,
        query: gql`
        query allCricketers($searchTerm: String){
          allCricketers(searchTerm: $searchTerm){
            name
            id
            country
            age
          }
        }
        `,
        variables: {
          searchTerm: searchTerm
        }
      })
      .valueChanges.pipe(map(result => {
        return result.data.allCricketers;
      }));
  }

  getCricketer(id: String) {
    return this.apollo
      .watchQuery<Query>({
        query: gql`
          query getCricketer($id: String!){
            getCricketer(id: $id) {
              name
              id
              country
            }
          }
      `,
        variables: {
          id: id
        }
      })
      .valueChanges.pipe(map(result => {
        console.log(result.data.getCricketer);
        return result.data.getCricketer;
      }));
  }

  addCricketer(name: String, country: String, age: Number) {
    return this.apollo.mutate({
      mutation: gql`
        mutation addCricketer(name: $name,country: $country, age: $age){
          id
          name
          country
          age
        }
      `,
      variables: {
        name: name,
        country: country,
        age: age
      }
    });
  }

  updateCricketer(id: String, name: String, country: String, age: Number) {
    return this.apollo.mutate({
      mutation: gql`
          mutation updateCricketer(id: $id , name: $name,country: $country, age: $age){
            id
            name
            country
            age
          }
        `,
      variables: {
        id: id,
        name: name,
        country: country,
        age: age
      }
    });
  }

  updateSearchTerm(searchInput: String) {
    this.searchInput.next(searchInput);
  }

  getSearchTerm() {
    return this.searchInput.asObservable();
  }
}

Component using resolver:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-cricketer-detail',
  templateUrl: './cricketer-detail.component.html',
  styleUrls: ['./cricketer-detail.component.css']
})
export class CricketerDetailComponent implements OnInit {
  cricketer: any;
  constructor(private route: ActivatedRoute) { }

  ngOnInit() {
    this.cricketer = this.route.snapshot.data.cricketer;
  }

}
1

There are 1 answers

0
Nirmal On

Solved this by using the query method instead of watchQuery method. The watchQuery does not complete since it can emit multiple results. So the resolver did not receive the observable and did not resolve the route.

One of the members of the apollo-graphql team

With query() you fetch data, receive the result, then an Observable completes.

With watchQuery() you fetch data, receive the result and an Observable is keep opened for new emissions so it never completes.

From Docs

Apollo.query method returns an Observable that emits a result, just once

Apollo.watchQuery also does the same, except it can emit multiple results. (The GraphQL query itself is still only sent once, but the watchQuery observable can also update if, for example, another query causes the object to be updated within Apollo Client’s global cache.)

Ref- https://github.com/apollographql/apollo-angular/issues/280