Search code examples
javascriptangulartypescriptgoogle-api-clientangular2-services

Google API Endpoints using Javascript client library as an Angular 2 Service


I am using Google API Javascript library in my Angular 2 application. I have created a service which is injected in components. Here is the code:

import { Injectable } from '@angular/core';
const url = 'https://apis.google.com/js/client.js?onload=__onGoogleLoaded';
@Injectable()
export class GoogleAPIService {
 public client: any;
 public calculatorService: any;
 public actionService: any;
loadAPI: Promise<any>
      constructor(){
        this.loadAPI = new Promise((resolve) => {
          window['__onGoogleLoaded'] = (ev) => {
            console.log('gapi loaded');
            resolve(window['gapi']);
            this.client = window['gapi'].client;
            this.loadEndPoints('{Endpoint URL}/_ah/api');
          }
          this.loadScript();
        });

      }

      doSomethingGoogley(){
        return this.loadAPI.then((gapi) => {
          console.log(gapi);
        });
      }

      loadScript(){
        console.log('loading..')
        let node = document.createElement('script');
        node.src = url;
        node.type = 'text/javascript';
        document.getElementsByTagName('head')[0].appendChild(node);

      }

      loadEndPoints(apiRoot) {
  // Loads the OAuth and calculatorendpoint APIs asynchronously, and triggers login
  // when they have completed.
  var apisToLoad;
  var callback = function() {
    console.log('API Loaded '+apisToLoad);
    if (--apisToLoad == 0) {
      //this.endpoint1= this.client.endpoint1; //Doesn't Work
      //this.endpoint2= this.client.endpoint2; 
    }

  }

  apisToLoad = 3; // must match number of calls to gapi.client.load()
  this.client.load('oauth2', 'v2', callback);  
  this.client.load('endpoint1', 'v1', callback, apiRoot);
  this.client.load('endpoint2','v1',callback,apiRoot);

  }
}

I have three questions:

  1. How do I get the endpoints gapi.client.endpoint1 as a public variable in the service?
  2. How do I call the methods in the api? In javascript, u can jst call gapi.client.endpoint1.method().execute()
  3. How do I make this service singleton?

Any help is appreciated.

EDIT:

Here is the working version of the service. I use it as provider in my Root module. thus, its available as singleton throughout the application.

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

const url = 'https://apis.google.com/js/client.js?onload=__onGoogleLoaded';
const gapiOnLoaded = '__onGoogleLoaded';
const clientName = 'gapi';
const endpointhost = '[HTTPS URL FOR ENDPOINTS]';
const apiEndPoint = endpointhost + '/_ah/api';
@Injectable()
export class GoogleAPIService {
  private gapi: any;
  private loadAPI: Promise<any>;
  constructor() {
    this.loadAPI = new Promise((resolve) => {
        window[gapiOnLoaded] = (ev) => {
        this.gapi = window[clientName];
        // Loads the OAuth and other APIs asynchronously, and triggers login
        // when they have completed.
        let apisToLoad;
        let callback = function() {
        if (--apisToLoad === 0) {
            resolve(window[clientName]);
          }
        };
        apisToLoad = 3; // must match number of calls to gapi.client.load()
        this.gapi.load('client:auth2', callback);
        this.gapi.client.load('[ENDPOINT_1_NAME]', 'v1', callback, apiEndPoint);
        this.gapi.client.load('[ENDPOINT_2_NAME]', 'v1', callback, apiEndPoint);
      };
      this.loadScript();
    });
  }

  public GetClient(): any {
        return   this.loadAPI.then((res) => {
              return this.gapi;
          });
  }

  private loadScript()  {
    let node = document.createElement('script');
    node.src = url;
    node.type = 'text/javascript';
    document.getElementsByTagName('head')[0].appendChild(node);
  }
}

Inject this service in other services. I created a service for each of the endpoints.

@Injectable()
export class Endpoint1Service {
    private gapi: any;
    constructor(private googleApiService: GoogleAPIService) {
    }

    public isLoad() {
        return this.googleApiService.GetClient().then((gapi) => {
                this.gapi = gapi;
                return true;
            });
    }

    public action(data: DataType){
        this.gapi.client.endpointname.apimethod(data).execute();
    }
}

Solution

  • Services are singletons by default. You should provide it in your AppModule, and then it will be available to all of your components. Just make sure to include it in your component constructors.

    import {NgModule} from '@angular/core';
    import {BrowserModule} from '@angular/platform-browser';
    import {HttpModule} from '@angular/http';
    
    import { AppComponent } from './app.component';
    import { routing } from './app.routing'; 
    import { GoogleService } from './google.service'; // important
    
    @NgModule({
        imports: [
            BrowserModule,
            HttpModule,
            routing,
        ],
        declarations: [ AppComponent],
        providers: [ GoogleService ], // important
        bootstrap: [ AppComponent],
    })
    export class  AppModule {
    }
    

    To make an endpoint available outside of your service, you can use the public keyword in front of the function that calls the endpoint. To call the endpoint in angular2, you can use the built-in http service from @angular/http. Here's an example service (only using HTTP GET) that will return an Observable for the endpoints you call.

    import { Injectable } from '@angular/core';
    import { Http } from '@angular/http';
    import { Observable } from 'rxjs';
    
    @Injectable()
    export class GoogleService {
    
        constructor(private http: Http) { }
    
        public endpoint1(): Observable<any> {
            return this.http.get("http://endpoint.one.com");
        }
    
        public endpoint2(): Observable<any> {
            return this.http.get("http://endpoint.two.com");
        }
    
    }
    

    You can then use the service like this in your component.

    import { Component, OnInit } from '@angular/core';
    import { GoogleService } from './google.service'; // important
    
    @Component({
        selector: 'app',
        templateUrl: 'app.component.html'
    })
    export class AppComponent implements OnInit {
        constructor(private googleService: GoogleService) { }
    
        ngOnInit() {
    
            this.googleService.endpoint1().subscribe(callback1, handleError);
    
            this.googleService.endpoint2().subscribe(callback2, handleError);
    
        }
    
        callback1(data){
            // do something with the data from ONE
        }
    
        callback2(data){
            // do something with the data from TWO
        }
    
        handleError(error: any){
            console.error(error);
        }
    
    }
    

    I recommend reading up a bit on using Observables in this post from Angular University.