2016-11-28 1 views
2

J'essaie d'implémenter un service qui utilisera l'API Google pour connecter l'utilisateur et autoriser l'API Sheets. Une version simplifiée de ce service:Affichage non mis à jour après modification dans le rappel de l'API Google

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

Je suis injection ce service à mon AppComponent comme private myService: MyService. Dans mon app.component.html j'ai un simple bouton qui devrait être visible si l'utilisateur n'a pas autorisé l'API:

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

Alors ce que je veux est: - Le service appelle gapi.auth.authorize - Si l'utilisateur a autorisé la API, puis isLoggedIn doit être défini sur true et le bouton doit disparaître - Si l'autorisation immédiate échoue, le bouton doit être visible afin que l'utilisateur puisse déclencher l'autorisation manuellement. Le problème auquel je suis confronté est que lorsque l'autorisation immédiate réussit et que «Utilisateur connecté, vrai» est imprimé dans la fenêtre de la console, le bouton reste visible. La liaison *ngIf ne fonctionne pas. La modification dans isLoggedIn n'est pas reflétée. J'ai trouvé un poste similaire here in SO mais j'avais déjà soupçonné qu'il pourrait avoir à faire avec les rappels, donc j'avais déjà essayé de changer la valeur d'un setTimeout dans un setTimeout dans un autre setTimeout et la mise à jour avec succès.

J'ai finalement trouvé une solution en injectant ChangeDetectorRef comme private detector et en appelant detector.detectChanges() après avoir défini une valeur pour isLoggedIn. Je ne demande pas de solution, je demande si quelqu'un sait pourquoi ce comportement bizarre se produit et pourquoi dois-je utiliser le détecteur de changement pour une opération qui, à mon avis, ressemble à quelque chose qui devrait être géré par Angular lui-même. Ou est-ce que je manque quelque chose et que ce comportement est normal?

Répondre

1

gapi n'est pas couvert par Zone.js. Vous devez invoquer explicitement la détection de changement:

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

Oui c'est exactement ce que j'ai fait et cela a fonctionné. Donc, tout cela a à voir avec le fonctionnement de Zone? – dimlucas

+0

Je suppose que c'est parce que vous initialisez gapi en dehors de Angular, donc NgZone n'est pas au courant de ses appels d'API asynchrones. Il est également possible si vous l'initialisez dans Angular qu'il traite en quelque sorte les événements sans remarquer la zone. NgZone ne couvre pas 100% de toutes les possibilités. –