Reputation: 21
I am trying to guard URLs based on whether the user has the status admin (isAdmin = true). The service AdminAuthGuard checks whether the user has such admin status by calling the get(uid) function in the service UserService. This get function calls the AppUser interface that outlines the relevant fields.
The data are retrieved from a Firebase database using AngularFire 2. See below for version details.
The errors that I'm getting are:
ERROR in src/app/admin-auth-guard.service.ts(21,17): error TS2345: Argument of type '(user: {}) => AngularFireObject<AppUser>' is not assignable to parameter of type '(value: {}, index: number) => ObservableInput<{}>'.
Type 'AngularFireObject<AppUser>' is not assignable to type 'ObservableInput<{}>'.
Type 'AngularFireObject<AppUser>' is not assignable to type 'Iterable<{}>'.
Property '[Symbol.iterator]' is missing in type 'AngularFireObject<AppUser>'.
src/app/admin-auth-guard.service.ts(21,51): error TS2339: Property 'uid' does not exist on type '{}'.
The line that the errors seem the refer to is:
switchMap(user => this.userService.get(user.uid))
My system setup:
Angular CLI: 6.0.1
Node: 10.1.0
rxjs: 6.1.0
Firebase: 5.0.2
AngularFire2: 5.0.0-rc.8.0
admin-auth-guard.service.ts
import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
import { Observable } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { AuthService } from './auth.service';
import { UserService } from './user.service';
import { AppUser } from './models/app-user';
@Injectable({
providedIn: 'root'
})
export class AdminAuthGuard implements CanActivate {
constructor(private userService: UserService, private auth: AuthService) { }
canActivate(): Observable<boolean> {
return this.auth.user$.pipe(
switchMap(user => this.userService.get(user.uid))
.map(appUser => appUser.isAdmin)
);
}
}
user.service.ts
import { Injectable } from '@angular/core';
import { AngularFireDatabase, AngularFireObject } from 'angularfire2/database';
import * as firebase from 'firebase';
import { AppUser } from './models/app-user';
@Injectable({
providedIn: 'root'
})
export class UserService {
constructor(private db: AngularFireDatabase) { }
get(uid: string): AngularFireObject<AppUser> {
return this.db.object('/users/' + uid);
}
}
app-user.ts (model for users)
export interface AppUser {
name: string;
email: string;
isActive: boolean;
}
Upvotes: 2
Views: 890
Reputation: 959
Thanks to user4807496, their solution worked for me, and I see the main difference is due to adding valueChanges()
after get(user.uid)
However, mine has a few modifications based on the latest version of angular having no null fields. In order to make sure what you fetch is not null you need to add an exclamation mark.
Also, you do not need to have two pipes chained together, you can simply put both switchMap and map within one pipe and separate them with a comma. (see more in the rxjs pipeable operators docs)
export class AdminAuthGuardService implements CanActivate{
constructor(private auth: AuthService, private userService: UserService){ }
canActivate(): Observable<boolean> {
return this.auth.user$
.pipe(
switchMap( user => this.userService.get(user!.uid).valueChanges()),
map(appUser => appUser!.isAdmin)
);
}
}
Upvotes: 0
Reputation: 41
I found answer here Working with AngularFireObject and switchMap
canActivate(): Observable<boolean>{
return this.auth.user$
.pipe(switchMap(user => this.userService.get(user.uid).valueChanges()))
.pipe(map (appUser => appUser.isAdmin)); }
Upvotes: 3
Reputation: 5254
You are getting the error because you are using Array.map
and not rxjs map. You have to use the new syntax with pipe
canActivate(): Observable<boolean> {
return this.auth.user$.pipe(
switchMap(user => this.userService.get(user.uid))
.pipe(
map(appUser => appUser.isAdmin)
)
);
}
Upvotes: 1