I'm new in Angular and also a bit lost. I'm trying to implement the google sign on in an angular app but i cannot make it work. The idea is to show the sign in button and once the user has completed it, refresh the component showing his data and photo.
I managed to init the gApi and subscribe to login events by using their methods, but i don't know how to make the component to reload after the corresponding listener is called. I have been trying using subject.AsObservable() -> subscription to try to deal with this, and even if i know the callback is called, the component is not updated.
A friend told me to use EventEmmitter to deal with this, but as the callback is inside a service and i don't need to reload the parent, i'm not sure if this is will work.
Also i'm reading about ngZones which could make the trick (but i'm not sure if this a kind of anti-pattern). I write here the code i have now.
header.html
<div *ngIf="this.loggedIn else showLogin">
<p>{{this.getBasicProfile().getName()}}</p>
<p>{{this.getBasicProfile().getEmail()}}</p>
<img [src]="this.getBasicProfile().getImageUrl()"/>
</div>
<ng-template #showLogin>
{{this.loggedIn}}
<div class="g-signin2"></div>
</ng-template>
header.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { GoogleService } from '../google.service'
import { Subscription } from 'rxjs';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.sass']
})
export class HeaderComponent implements OnInit, OnDestroy {
constructor(protected google : GoogleService) {
}
loggedIn: boolean = false;
subscription : Subscription;
getBasicProfile() {
return this.google.getUserProfile();
}
ngOnInit(): void {
this.subscription = this.google.loggedIn$.subscribe(loggedIn => {
this.loggedIn = loggedIn;
});
this.google.init().then(() => {
this.google.listenUserChanges();
});
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
}
google.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject, Subscriber } from 'rxjs';
declare const gapi: any;
@Injectable({
providedIn: 'root'
})
export class GoogleService {
private loggedIn: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
auth: any;
profile: any;
loggedIn$ = this.loggedIn.asObservable();
public init(): Promise<boolean> {
let doInit = new Promise<boolean>((resolve, reject) => {
gapi.load('auth2', () => {
gapi.auth2.init({
client_id: "XXXXXX.apps.googleusercontent.com",
cookiepolicy: 'single_host_origin',
}).then(auth => {
this.auth = auth;
resolve();
});
});
});
return doInit;
}
public listenUserChanges(): void {
if (!this.isLoggedIn()) {
this.auth.isSignedIn.listen(() => {
this.getUserProfile()
});
this.auth.currentUser.listen(() => {
this.getUserProfile()
});
}
}
public isLoggedIn(): boolean {
if (this.auth) {
let isLoggedIn = this.auth.isSignedIn.get();
this.loggedIn.next(isLoggedIn);
return isLoggedIn;
}
return false;
}
public getUserProfile(): any {
if (this.auth && this.isLoggedIn()) {
this.profile = this.auth.currentUser.get().getBasicProfile();
return this.profile;
}
return null;
}
constructor() {
this.auth = null;
}
}
any suggestion will be more than welcomed.
thanks!!
As @amakhrov suggested using ngZone.run() i was able to update the component when finishing the sign on with google API. Also the idea of doing the refactor to avoid unecessary updates using Subscription model was interesting, Thanks!