从 Google API 加载 auth2 时,更改检测不会运行

2024-01-05

我正在尝试加载脚本https://apis.google.com/js/api.js?onload=initGapi从 Angular 2 服务中调用 Google API,但是每当我尝试在脚本加载和初始化完成后返回一个值时,asyncPipe 不想将值呈现给模板。

我正在使用一个EventEmittergapi.load() and gapi.client.init已完成,并且可观察对象在组件中订阅它。异步管道似乎不想读取该值,直到我单击同一组件中的按钮(可能还触发更改检测)。当我使用时,强制组件内的更改检测不起作用tick() from ApplicationRef.

加载 Google API 的服务如下:

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

以及从服务中读取的组件

应用程序组件.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当我期望的时候。

有谁知道我如何使用异步管道来获取hello world打印到页面时authEmitter触发一个事件。


我最终找到了这个问题的解决方案,这个问题有几个问题。

首先,EventEmitter应该只用于发出,并且永远不应该被订阅,所以我用一个Subject。通常我会尝试使用可观察的,但在这种情况下我发现一个更合适的主题。

下面是一个修改后的 plunker,使用Subject代替EventEmitter。我也注释掉了gapi.client.init...并用不同的承诺替换它,因为它实际上不是问题的一部分。请注意,在 plunker 中,直到单击按钮才运行更改检测,这不是预期的。

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

我遇到的问题是因为gapi.load('client:auth2', this.initClient.bind(this)); runs initClient在 Angular 2 区域之外,这会将其排除在更改检测之外。

为了捕获变化检测中的主题,我们必须运行主题的next and complete在 Angular 2 区域内调用。这是通过导入完成的NgZone然后修改行:

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

请参阅此处的最终(已解决)plunker。 https://plnkr.co/edit/w2UBDiLO7fSoANhLZPEA?p=preview

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从 Google API 加载 auth2 时,更改检测不会运行 的相关文章

随机推荐