Reputation: 472
I want to extract the name from Auth0 userProfile$ after login. So I can use it to create a consultant in our db. I am not so familiar with observable and subscribe. I tried to use it in the code you can see below. When I log inside subscribe I can see the name that I want to add to my post req. But when I try to use it it just gives me an empty subscription.
dashboard.component.ts
```typescript
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { ApiService } from '../services/api.service';
import { AuthService } from 'src/app/auth/auth.service';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss'],
})
export class DashboardComponent implements OnInit {
id= '';
navigateSkillplatform() {
this.router.navigate(['skillplatform', this.id]);
}
constructor(private router: Router, private api: ApiService, private auth: AuthService) {}
ngOnInit(): void {
var consultant = { Name: this.auth.userProfile$.subscribe(consultant => console.log("test", consultant.name)) };
console.log(consultant.Name)
// if (this.auth.loggedIn) {
// this.api.createConsultant(consultant).subscribe(
// response => {
// console.log("POST create consultant response:," ,
// response);
// })
// }
}
}
```
Browser console output
<pre>
dashboard.component.ts:24 test Imke Van Rompa
dashboard.component.ts:25
Subscriber {closed: false, _parentOrParents: null, _subscriptions: Array(1), syncErrorValue: null, syncErrorThrown: false, …}
closed: false
_parentOrParents: null
_subscriptions: [SubjectSubscription]
syncErrorValue: null
syncErrorThrown: false
syncErrorThrowable: true
isStopped: false
destination: SafeSubscriber {closed: false, _parentOrParents: null, _subscriptions: null, syncErrorValue: null, syncErrorThrown: false, …}
__proto__: Subscription
</pre>
Auth.service
```
import { Injectable } from '@angular/core';
import createAuth0Client from '@auth0/auth0-spa-js';
import Auth0Client from '@auth0/auth0-spa-js/dist/typings/Auth0Client';
import { authConfig } from '../../environments/environment';
import { from, of, Observable, BehaviorSubject, combineLatest, throwError } from 'rxjs';
import { tap, catchError, concatMap, shareReplay } from 'rxjs/operators';
import { Router } from '@angular/router';
@Injectable({
providedIn: 'root',
})
export class AuthService {
// Create an observable of Auth0 instance of client
auth0Client$ = (from(
createAuth0Client({
domain: authConfig.domain,
client_id: authConfig.clientId,
redirect_uri: `${window.location.origin}`,
audience: authConfig.audience,
})
) as Observable<Auth0Client>).pipe(
shareReplay(1), // Every subscription receives the same shared value
catchError(err => throwError(err))
);
// Manage Acces Token
// Observable method to retrieve access token and make it available for use in application
getTokenSilently$(options?): Observable<string> {
return this.auth0Client$.pipe(
concatMap((client: Auth0Client) => from(client.getTokenSilently(options)))
);
}
// Define observables for SDK methods that return promises by default
// For each Auth0 SDK method, first ensure the client instance is ready
// concatMap: Using the client instance, call SDK method; SDK returns a promise
// from: Convert that resulting promise into an observable
isAuthenticated$ = this.auth0Client$.pipe(
concatMap((client: Auth0Client) => from(client.isAuthenticated())),
tap(res => (this.loggedIn = res))
);
handleRedirectCallback$ = this.auth0Client$.pipe(
concatMap((client: Auth0Client) => from(client.handleRedirectCallback()))
);
// Create subject and public observable of user profile data
private userProfileSubject$ = new BehaviorSubject<any>(null);
userProfile$ = this.userProfileSubject$.asObservable();
// Create a local property for login status
loggedIn: boolean = null;
constructor(private router: Router) {
// On initial load, check authentication state with authorization server
// Set up local auth streams if user is already authenticated
this.localAuthSetup();
// Handle redirect from Auth0 login
this.handleAuthCallback();
}
// When calling, options can be passed if desired
// https://auth0.github.io/auth0-spa-js/classes/auth0client.html#getuser
getUser$(options?): Observable<any> {
return this.auth0Client$.pipe(
concatMap((client: Auth0Client) => from(client.getUser(options))),
tap(user => this.userProfileSubject$.next(user))
);
}
private localAuthSetup() {
// This should only be called on app initialization
// Set up local authentication streams
const checkAuth$ = this.isAuthenticated$.pipe(
concatMap((loggedIn: boolean) => {
if (loggedIn) {
// If authenticated, get user and set in app
// NOTE: you could pass options here if needed
return this.getUser$();
}
// If not authenticated, return stream that emits 'false'
return of(loggedIn);
})
);
checkAuth$.subscribe();
}
login(redirectPath: string = '/') {
// A desired redirect path can be passed to login method
// (e.g., from a route guard)
// Ensure Auth0 client instance exists
this.auth0Client$.subscribe((client: Auth0Client) => {
// Call method to log in
client.loginWithRedirect({
redirect_uri: `${window.location.origin}`,
appState: { target: redirectPath },
});
});
}
private handleAuthCallback() {
// Call when app reloads after user logs in with Auth0
const params = window.location.search;
if (params.includes('code=') && params.includes('state=')) {
let targetRoute: string; // Path to redirect to after login processsed
const authComplete$ = this.handleRedirectCallback$.pipe(
// Have client, now call method to handle auth callback redirect
tap(cbRes => {
// Get and set target redirect route from callback results
targetRoute = cbRes.appState && cbRes.appState.target ? cbRes.appState.target : '/';
}),
concatMap(() => {
// Redirect callback complete; get user and login status
return combineLatest([this.getUser$(), this.isAuthenticated$]);
})
);
// Subscribe to authentication completion observable
// Response will be an array of user and login status
authComplete$.subscribe(([user, loggedIn]) => {
// Redirect to target route after callback processing
this.router.navigate([targetRoute]);
});
}
}
logout() {
// Ensure Auth0 client instance exists
this.auth0Client$.subscribe((client: Auth0Client) => {
// Call method to log out
client.logout({
client_id: authConfig.clientId,
returnTo: window.location.origin,
});
});
}
}
```
I am sure there is going to be a simple answer for this that I just didn't think of yet.
Upvotes: 0
Views: 1364
Reputation: 507
Try something like this:
export class DashboardComponent implements OnInit {
id= '';
consultantName;
navigateSkillplatform() {
this.router.navigate(['skillplatform', this.id]);
}
constructor(private router: Router, private api: ApiService, private auth: AuthService)
{}
ngOnInit(): void {
this.auth.userProfile$.subscribe(consultant => this.consultantName = consultant.name);
console.log(this.consultantName)
// Now you have name for your consultant and you can make post to your db
if (this.auth.loggedIn && this.consultantName) {
this.api.createConsultant(this.consultantName).subscribe(
response => {
console.log("POST create consultant response:," ,
response);
})
}
}
}
Upvotes: 2
Reputation: 2916
Maybe use should change
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { ApiService } from '../services/api.service';
import { AuthService } from 'src/app/auth/auth.service';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss'],
})
export class DashboardComponent implements OnInit {
id= '';
navigateSkillplatform() {
this.router.navigate(['skillplatform', this.id]);
}
constructor(private router: Router, private api: ApiService, private auth: AuthService) {}
ngOnInit(): void {
var consultant = { Name: this.auth.userProfile$.subscribe(consultant => console.log("test", consultant.name)) };
console.log(consultant.Name)
// if (this.auth.loggedIn) {
// this.api.createConsultant(consultant).subscribe(
// response => {
// console.log("POST create consultant response:," ,
// response);
// })
// }
}
}
To
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Router } from '@angular/router';
import { ApiService } from '../services/api.service';
import { AuthService } from 'src/app/auth/auth.service';
import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss'],
})
export class DashboardComponent implements OnInit, OnDestroy {
id= '';
consultant = null;
onDestroy = new Subject<void>();
navigateSkillplatform() {
this.router.navigate(['skillplatform', this.id]);
}
constructor(private router: Router, private api: ApiService, private auth: AuthService) {}
ngOnInit(): void {
this.auth.userProfile$.pipe(takeUntil(this.onDestroy)).subscribe(consultant =>
this.consultant = consultant;
// Do whaterever you want with the user.
console.log(this.consultant)
);
}
}
ngOnDestroy() { this.onDestroy.emit(); }
}
Upvotes: 0
Reputation: 2171
I think you should just subscribe and map to name inside subscription.
ngOnInit(): void {
const consultant = {}
this.auth.userProfile$.subscribe(result=> {
console.log("test", result.name)
consultant.name = result.name
});
}
Upvotes: 3