在 Google API 回调中更改后视图未更新

View not updating after change in Google API callback

我正在尝试实施一项服务,该服务将使用 Google API 来让用户登录并授权表格 API。该服务的简化版本:

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

declare var gapi;

@Injectable()
export class MyService{
    isLoggedIn: boolean = false;
    clientId: string = "*******.apps.googleusercontent.com";
    scopes: string[] = ["https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/drive"];


    constructor(){
        gapi.load('client', () => {
            console.log("Client Loaded");
            gapi.auth.authorize({
                client_id: this.clientId,
                scope: this.scopes.join(' '),
                immediate: true
            }, (authResponse) => {
                if(authResponse && !authResponse.error){
                    this.isLoggedIn = true;
                    console.log("User logged in, " + this.isLoggedIn);
                }
                else{
                    this.isLoggedIn = false;
                    console.log("User not logged in");
                    console.log(this.isLoggedIn);
                }
            });
        });
    }
}

我将该服务作为 private myService: MyService 注入到我的 AppComponent 中。在我的 app.component.html 中,我有一个简单的按钮,如果用户未授权 API:

,该按钮应该可见

<button *ngIf="!myService.isLoggedIn">Authorize</button>

所以我想要的是: - 服务调用 gapi.auth.authorize - 如果用户已授权 API,则 isLoggedIn 应设置为 true,按钮应消失 - 如果立即授权失败,该按钮应该可见,以便用户可以手动触发授权。

我面临的问题是,当立即授权成功并且 "User logged in, true" 打印在控制台 window 中时,该按钮仍然可见。 *ngIf 绑定不起作用。 isLoggedIn 中的更改未反映出来。我发现了一个类似的 post ,但我已经怀疑它可能与回调有关,所以我已经尝试在 setTimeout 中更改 setTimeout 的值在另一个 setTimeout 中,视图成功更新。

我终于找到了解决方案,将 ChangeDetectorRef 注入 private detector 并在为 isLoggedIn 设置值后调用 detector.detectChanges()

所以我不是在寻求解决方案,我想问的是是否有人知道为什么会发生这种奇怪的行为,以及为什么我必须使用变化检测器来进行至少对我来说似乎是这样的操作就像应该由 Angular 自己处理的事情。还是我遗漏了什么而这种行为是正常的?

gapi 未包含在 Zone.js 中。您需要显式调用更改检测:

constructor(private cdRef:ChangeDetectorRef){
    gapi.load('client', () => {
        console.log("Client Loaded");
        gapi.auth.authorize({
            client_id: this.clientId,
            scope: this.scopes.join(' '),
            immediate: true
        }, (authResponse) => {
            if(authResponse && !authResponse.error){
                this.isLoggedIn = true;
                console.log("User logged in, " + this.isLoggedIn);
            }
            else{
                this.isLoggedIn = false;
                console.log("User not logged in");
                console.log(this.isLoggedIn);
            }
            cdRef.detectChanges(); // <<<< added
        });
    });
}