Zoe
Zoe

Reputation: 21

AngularFire2: Issues with Observable

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

Answers (3)

Kingston Fortune
Kingston Fortune

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

user4807496
user4807496

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

CornelC
CornelC

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

Related Questions