2

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;
}

3 Answers 3

3

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));    }
Sign up to request clarification or add additional context in comments.

Comments

1

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)
    )
  );
}

1 Comment

Hello. Thank you for helping. I made the changes but now get the following errors instead: (see answer below because of limited space)
0

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)
   );
  }

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.