Google API-endpunkter som använder JavaScript-klientbiblioteket som en Angular 2-tjänst


Jag använder Google API Javascript-biblioteket i min Angular 2-applikation. Jag har skapat en tjänst som injiceras i komponenter. Här är koden:

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);

  }
}

Jag har tre frågor:

  1. Hur får jag ändpunkterna gapi.client.endpoint1 som en offentlig variabel i tjänsten?
  2. Hur anropar jag metoderna i API:et? I JavaScript kan du bara anropa gapi.client.endpoint1.method().execute()
  3. Hur gör jag den här tjänsten till en singleton?

All hjälp uppskattas.

REDIGERA:

Här är den fungerande versionen av tjänsten. Jag använder den som leverantör i min Root-modul. Därför är den tillgänglig som singleton i hela applikationen.

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);
  }
}

Injicera denna tjänst i andra tjänster. Jag skapade en tjänst för varje slutpunkt.

@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();
    }
}

Svar #1

Tjänster är singletons som standard. Du bör provide den i din AppModule, och då kommer den att vara tillgänglig för alla dina komponenter. Se bara till att inkludera den i dina komponentkonstruktörer.

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 {
}

För att göra en slutpunkt tillgänglig utanför din tjänst kan du använda sökordet public framför funktionen som anropar slutpunkten. För att anropa slutpunkten i angular2 kan du använda den inbyggda http-tjänsten från @angular/http. Här är ett exempel på en tjänst (endast med HTTP GET) som kommer att returnera ett Observable för de slutpunkter du anropar.

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");
    }

}

Du kan sedan använda tjänsten så här i din komponent.

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);
    }

}

Jag rekommenderar att läsa lite om att använda Observables i det här inlägget från Angular University.

Svar #2

Jag tror inte att det är särskilt bra praxis att modifiera DOM för att ladda gapi. Det är troligen bättre att använda gapi och gapi.auth TypeScript-definitioner genom att installera dem med NPM.

Jag har lagt upp instruktioner om hur man gör detta i mitt svar på Import gapi.auth2 i Angular 2 TypeScript.

Relaterade artiklar