I'm making a youtube playlist project with Gooogle OAuth, I met a little issue while handling the authentication process, the variable isAuthorized
is where I store the user sign-in state, I can see in the console that it's changed to true after user sign in, but it's still false in the View section. I wonder how exactly I solve this?
below is my code for the Model section
GoogleAuth: any;
user: any;
isAuthorized = false;
ngOnInit(): void {
// Load auth2 library
gapi.load("client:auth2", this.initClient);
}
loadClient = () => {
gapi.client.setApiKey(this.API_KEY);
return gapi.client
// same as "https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest"
.load("youtube", "v3")
.then(
() => {
console.log("GAPI client loaded for API");
},
function (err) {
console.error("Error loading GAPI client for API", err);
}
);
}
// Init API client library and set up sign in listeners
initClient = () => {
gapi.client
.init({
discoveryDocs: this.DISCOVERY_DOCS,
clientId: this.CLIENT_ID,
scope: this.SCOPES,
})
.then(() => {
this.GoogleAuth = gapi.auth2.getAuthInstance();
// Listen for sign-in state changes.
this.GoogleAuth.isSignedIn.listen(this.handleSigninStatus);
// Handle initial sign-in state. (Determine if user is already signed in.)
this.handleSigninStatus();
this.loadClient()
});
}
handleSigninStatus = () => {
this.user = this.GoogleAuth.currentUser.get();
this.isAuthorized = this.user.hasGrantedScopes(this.SCOPES);
if (this.isAuthorized) {
this.loadClient()
// this.getChannelInfo() //display playlist data
} else {
//do nothing
}
}
// Handle login
handleAuthClick = () => {
this.GoogleAuth.signIn({ scope: this.SCOPES })
.then(() => {
console.log("Sign-in successful");
// this.isLoggedIn = true
this.getChannelInfo()
},
(err: any) => { console.error("Error signing in", { err }) });
}
// Handle logout
handleSignoutClick = () => {
this.GoogleAuth.signOut();
this.GoogleAuth.disconnect();
// gapi.auth2.getAuthInstance().signOut().then(() => { this.googleUser = null });
}
and this is my HTML, aka the View section:
<mat-toolbar>
<a href="/">My Application {{isAuthorized}}</a>
<ng-template [ngIf]="isAuthorized" [ngIfElse]="loggedOut">
<button mat-raised-button color="warn" id="signout-button" (click)="handleSignoutClick()">Log Out</button>
</ng-template>
<ng-template #loggedOut>
<button mat-raised-button color="warn" id="authorize-button" (click)="handleAuthClick()">Log In</button>
</ng-template>
</mat-toolbar>
CodePudding user response:
Because this.GoogleAuth
events operate out of angular's scope/zone you need to bring its callbacks into the angular zone. This way angular's lifecycle events will handle the changes on the data appropriately.
Wrap your event handler function(s) with ngZone's run function. This is advisable every time you are modifying an angular monitored variable via events that do not belong to the angular scope/zone:
constructor(private ngZone: NgZone ...
...
initClient = () => {
gapi.client
.init({
discoveryDocs: this.DISCOVERY_DOCS,
clientId: this.CLIENT_ID,
scope: this.SCOPES,
})
.then(() => {
this.ngZone.run(() => { // <-- here
this.GoogleAuth = gapi.auth2.getAuthInstance();
// Listen for sign-in state changes.
this.GoogleAuth.isSignedIn.listen(this.handleSigninStatus);
// Handle initial sign-in state. (Determine if user is already signed in.)
this.handleSigninStatus();
this.loadClient()
});
});
}
handleSigninStatus = () => {
this.ngZone.run(() => { // <-- here
this.user = this.GoogleAuth.currentUser.get();
this.isAuthorized = this.user.hasGrantedScopes(this.SCOPES);
if (this.isAuthorized) {
this.loadClient()
// this.getChannelInfo() //display playlist data
} else {
//do nothing
}
});
}
The easiest way to bring model modifications into the angular's scope/zone is to wrap them with a ngZone call like this one above.