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