1

Ich habe eine Angular2-App, die Login über Google oder Facebook mit Firebase (über AngularFire2) ermöglicht. Es ermöglicht auch die Verknüpfung von Konten, sodass ein Benutzer seine Google- und Facebook-Logins mit derselben Firebase-Nutzer-ID verknüpfen kann.Angular2 AngularFire2 providerData-Array nicht in Vorlage aktualisieren

In meiner ng2-Benutzerprofil-Komponente möchte ich für derzeit authentifizierte Benutzer eine Schaltfläche zum Verknüpfen eines FB- oder Google-Kontos anzeigen können, wenn sie nicht bereits verknüpft ist. AngularFire2 macht eine Observable vom Typ FirebaseAuthState verfügbar, die eine "auth" -Eigenschaft vom Typ Firebase.User enthält. Das firebase.User-Objekt enthält ein providerData-Array, das alle mit dem Benutzer verknüpften Anbieter (Facebook, Google, Github usw.) enthält. Mein AuthService sieht ungefähr so ​​aus:

import * as firebase from 'firebase'; 
import { Injectable } from '@angular/core'; 
import { AuthProviders, AuthMethods, 
     FirebaseAuth, FirebaseAuthState } from 'angularfire2'; 

@Injectable() 
export class AuthService { 

    authState: FirebaseAuthState = null; 

    constructor(private auth$: FirebaseAuth) { 
    auth$.subscribe((state) => {this.authState = state;}) 
    } 

    linkTo(provider:string): firebase.Promise<firebase.auth.UserCredential> { 
    // provider param is a string (e.g., ‘facebook.com’); 
    // linkWithPopup() returns a firebase promise of type firebase.AuthState 
    // Not included here: code to convert provider param from string to 
    // firebase.AuthProvider 
    return this.authState.auth.linkWithPopup(provider); 
    } 

    unLinkFrom(provider:string): firebase.Promise<firebase.auth.UserCredential> { 
    // provider is a string (e.g. ‘facebook.com’) 
    // unlink() returns a firebase promise of type firebase.User. 
    return this.authState.auth.unlink (provider); 
    } 

ich diese verwenden können, um welche Anbieter zu bestimmen, sind bereits mit einem bestimmten Benutzer zugeordnet werden, und verstecken/zeigen die erforderlichen Link Tasten je nachdem, ob ein Anbieter innerhalb der providerData Array des Benutzers enthalten ist . In meiner Komponente zum Beispiel:

export class UserProfileComponent implements OnInit { 

    private linkedProviders; 

    constructor() {} (private authService: AuthService) { 
    this. linkedProviders = authService.authState.auth.providerData; 
    } 
} 

Wenn ich einen Anbieter verknüpfen, gibt Firebase ein firebase.Promise-Objekt zurück. Bei erfolgreicher Verknüpfung verwende ich .then(), um das lokale Array linkedProviders zu aktualisieren, das das Array providerData von Firebase enthält. Zum Beispiel:

// Link a provider to the current account 
    linkProvider(provider:string) { 
    this.authService.linkTo(provider) 
     .then((state) => this.linkedProviders = state.user.providerData) 
     .catch(err => console.log(err)); 
    } 

    // Unlink a provider from the current account 
    unLinkProvider(provider:string) { 
    this.authService.unLinkAccount(provider) 
     .then(user => this.linkedProviders = user.providerData) 
     .catch(err => console.log(err)); 
    } 

jedoch die this.linkedProviders Array scheint nicht automatisch in der Vorlage zu aktualisieren mit * ngFor, wenn ein Benutzer der Links Solange LINK einen Anbieter, trotz der Tatsache, dass der .then() Block Der LinkProvider/unLinkProvider ändert ihn, um die aktualisierten Daten wiederzugeben, die vom Firebase-Versprechen zurückgegeben werden.

Eigentlich scheint es die lokalen Array-Daten zu ändern, als Protokollierung dieser.linkedProviders an der Konsole wird angezeigt. Wenn ich jedoch nicht auf eine andere Schaltfläche in der Vorlage klicke, wird die Änderung nicht auf die * ngFor angewendet. Ich kann mir nicht vorstellen, warum das passiert oder wie man damit umgehen kann. Ich bin sicher, dass ich etwas vermisse, aber ich kann nicht herausfinden, was.

+0

Ich denke, man cd.detectChanges http://stackoverflow.com/questions/40310021/angular2-change-detection-not-showing-unless-clicked verwenden, weil es außerhalb ngzone – yurzui

+0

ausgeführt wird, gearbeitet. Scheint ein wenig hacky, und ich würde es lieber im Dienst implementieren, wenn möglich. Ich muss etwas darüber nachforschen und versuchen, es herauszufinden. Danke, Yurzui. Das hat mich verrückt gemacht –

Antwort

0

Es könnte sauberer machen authState eine beobachtbare, so dass die Komponente es abonnieren kann. Die Komponente kann dann linkWithPopup aufrufen oder die Verknüpfung auf dem authState im Abonnement aufheben. Momentan sieht es so aus, als ob die Methoden linkTo und unlinkFrom aufgerufen werden können, bevor authState gesetzt wurde.

 import * as firebase from 'firebase'; 
     import { Injectable } from '@angular/core'; 
     import { 
      AuthProviders, AuthMethods, 
      FirebaseAuth, FirebaseAuthState 
     } from 'angularfire2'; 
     import { ReplaySubject } from 'rxjs/ReplaySubject'; 
     import { Observable } from 'rxjs/Observable'; 

     @Injectable() 
     export class AuthService { 
      private authStateSource = new ReplaySubject<FirebaseAuthState>(1); 
      authState: Observable<FirebaseAuthState> = this.authStateSource.asObservable(); 

      constructor(private auth$: FirebaseAuth) { 
       auth$.subscribe((state) => { 
        this.authStateSource.next(state); 
       }); 
      } 
     }