1

我試圖從Angular 2服務中加載腳本https://apis.google.com/js/api.js?onload=initGapi以調用Google API,但每當我嘗試返回值時腳本完成加載和初始化,async管道不想將值呈現給模板。當從Google API加載auth2時,更改檢測不會運行

我使用的EventEmittergapi.load()gapi.client.init完成時觸發,並且observable在組件中訂閱。異步管道似乎不想讀取值,直到我單擊相同組件內的按鈕(並可能觸發更改檢測)。當我使用ApplicationReftick()時,在組件內強制更改檢測不起作用。

與加載的谷歌API的服務如下:

谷歌,api.service.ts

import { Injectable, EventEmitter } from '@angular/core'; 
import { Observable } from 'rxjs/Observable'; 

import { User, Client } from '../../+home/models'; 

declare var gapi: any; 

@Injectable() 
export class GoogleApiService { 

    CLIENT_ID: string = '....apps.googleusercontent.com'; 
    DISCOVERY_DOCS: string[] = ["https://www.googleapis.com/discovery/v1/apis/admin/directory_v1/rest"]; 
    SCOPES = 'https://www.googleapis.com/auth/admin.directory.user.readonly'; 

    authEmitter: EventEmitter<boolean> = new EventEmitter(); 

    constructor() { 
     window['initGapi'] = (ev) => { 
      this.handleClientLoad(); 
     }; 
     this.loadScript(); 
    } 

    loadScript() { 
     let script = document.createElement('script'); 
     script.src = 'https://apis.google.com/js/api.js?onload=initGapi'; 
     script.type = 'text/javascript'; 
     document.getElementsByTagName('head')[0].appendChild(script); 
    } 

    handleClientLoad() { 
     gapi.load('client:auth2', this.initClient.bind(this)); 
    } 

    initClient() { 
     gapi.client.init({ 
      discoveryDocs: this.DISCOVERY_DOCS, 
      clientId: this.CLIENT_ID, 
      scope: this.SCOPES 
     }).then(() => { 
      this.authEmitter.emit(true); 
     }); 
    } 

    get gapi(): Observable<any> { 
     return this.authEmitter.map(() => 'hello world'); 
    } 
} 

和組件從服務

app.component閱讀.ts

import { Component, OnInit } from '@angular/core'; 
import { Observable } from 'rxjs/Observable'; 

import { GoogleApiService } from '../../+core/services'; 

@Component({ 
    template: ` 
    What does the service say? 
    {{ api$ | async }} 
    <button (click)="click()">Button</button>` 
}) 
export class InviteEmployeesContainer implements OnInit { 
    api$: Observable<string>; 

    constructor(private gApiService: GoogleApiService) {} 

    ngOnInit() { 
     this.api$ = this.gApiService.gapi; 

     this.gApiService.gapi.subscribe((result) => { 
      console.log(result); 
     }); 
    } 

    click() { 
     console.log('clicked'); 
    } 
} 

生成的頁面打印出字符串What does the service say?,並且有一個按鈕,但不會打印文本hello world,直到我點擊按鈕,這不是所需的行爲,它應該立即顯示在頁面上。

此外,當我訂閱並使用this.gApiService.gapi.subscribe登錄到控制檯時,它會記錄hello world,當我期望它。

是否有人知道如何在authEmitter觸發事件時使用異步管道將hello world打印到頁面。

+0

你嘗試直接返回它作爲一個getter'獲得API $(){回報this.service.gapi}'。您也可以嘗試使用ChangeDetectorRef來強制更改檢測。 – cyrix

+0

直接返回它並不好,因爲我不希望組件在它準備好之前使用它,它需要執行2個網絡請求並在可以使用之前運行'init',因此我使用了observable。我會嘗試強制更改檢測,但我不認爲這是一個實際的長期解決方案,因爲這通常是我期望可觀察到的事情來處理沒有問題。 – Adam

+0

您知道在準備就緒之前您可以使用'async'管道進行輸入,並且組件一旦發出數據就會立即開始使用它。 (因爲我看到你只是在它加載後才發出新的項目) – cyrix

回答

2

我最終找到了解決這個問題的辦法,這個問題有幾個問題。

首先,EventEmitter應該只用於發射,並且不應該訂閱,所以我換了一個Subject。通常我會嘗試使用可觀察的,但在這種情況下,我發現一個更合適的主題。

下面是使用Subject而不是EventEmitter修改後的重擊者。我也注意到gapi.client.init...,並用不同的承諾取而代之,因爲它實際上不是問題的一部分。請注意,在更換檢測器時,檢測仍然不會運行,直到點擊按鈕爲止,這並不是預期的結果。

https://plnkr.co/edit/YaFP07N6A4CQ3Zz1SbUi?p=preview

我遇到的問題是,因爲gapi.load('client:auth2', this.initClient.bind(this));運行initClient外的角2區,其中不包括從變化檢測的。

爲了捕獲更改檢測中的主題,我們必須在Angular 2區域內運行主題的nextcomplete調用。這是由進口NgZone,然後修改行完成:

new Promise((res) => res()).then(() => { 
     this.zone.run(() => { 
     this.authSubject.next(true); 
     this.authSubject.complete(true); 
     }); 
    }); 

See the final (resolved) plunker here.

相關問題