8

I really don't know how to fix this. How can I fix this error?

in user.service.ts:
import { Injectable } from '@angular/core';

import { AngularFireDatabase, AngularFireList, AngularFireObject } from 'angularfire2/database';

import {AppUser} from './models/app.user';
import * as firebase from 'firebase';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class UserService {


  constructor(private db: AngularFireDatabase) { }

  save(user: firebase.User) {
    this.db.object('/users/' + user.uid).update({
      name: user.displayName,
      email: user.email
    });
  }

  get(uid: string): AngularFireObject<AppUser> {
    return this.db.object('/users/' + uid);
  }



in admin-auth-guard.service:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/observable';
import 'rxjs/add/operator/switchMap';
import 'rxjs/operator/map';
import { UserService } from './user.service';
import { CanActivate } from '@angular/router';
import { AuthService } from './auth.service';



@Injectable({
  providedIn: 'root'
})
export class AdminAuthGuard  {

  constructor(private auth: AuthService, private userService: UserService) { }

   canActivate (): Observable<boolean> {
     return this.auth.user$
      .switchMap(user => this.userService.get(user.uid))<-- ERROR HERE
      .map (appUser => appUser.isAdmin);
    }
}

Argument of type '(user: User) => AngularFireObject' is not assignable to parameter of type '(value: User, index: number) => ObservableInput<{}>'. Type 'AngularFireObject' is not assignable to type 'ObservableInput<{}>'. Type 'AngularFireObject' is not assignable to type 'Iterable<{}>'. Property '[Symbol.iterator]' is missing in type 'AngularFireObject'.

Thanks.

4 Answers 4

17

Do it this way for Angular 6:

user.service.ts:

import { Injectable } from '@angular/core';

import { AngularFireDatabase, AngularFireObject } from 'angularfire2/database';

import {AppUser} from './models/app.user';
import * as firebase from 'firebase';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class UserService {


  constructor(private db: AngularFireDatabase) { }

  save(user: firebase.User) {
    this.db.object('/users/' + user.uid).update({
      name: user.displayName,
      email: user.email
    });
  }

  get(uid: string): AngularFireObject<AppUser> {
      return this.db.object('/users/' + uid);
  }

}



In admin-auth-guard.service.ts:


import { UserService } from './user.service';
import { map, switchMap } from 'rxjs/operators';
import { AuthService } from './auth.service';
import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class AdminAuthGuard 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()))
    .pipe(map(appUser => appUser.isAdmin));
   }

}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks a lot. This solved my problem. and worked in Angular 7 also.
If you are using pipe you don't need to add pipe again. Just separate the switchMap and map with a comma as pipe runs the composed functions in sequence.
7

I found the answer:

user.service.ts:

import { Injectable } from '@angular/core';

import { AngularFireDatabase, AngularFireObject } from 'angularfire2/database';

import {AppUser} from './models/app.user';
import * as firebase from 'firebase';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class UserService {


  constructor(private db: AngularFireDatabase) { }

  save(user: firebase.User) {
    this.db.object('/users/' + user.uid).update({
      name: user.displayName,
      email: user.email
    });
  }

  get(uid: string): AngularFireObject<AppUser> {
      return this.db.object('/users/' + uid);
  }

}

In admin-auth-guard.service.ts:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/observable';
import 'rxjs/add/operator/switchMap';
import 'rxjs/operator/map';
import { UserService } from './user.service';
import { CanActivate } from '@angular/router';
import { AuthService } from './auth.service';




@Injectable({
  providedIn: 'root'
})
export class AdminAuthGuard 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())))
      .pipe(map (appUser => appUser.isAdmin)));
     }
}

Thanks everybody!

3 Comments

thnx bro, ur answer helped me a lot
Thanks Vini, you are a life saver. Can you shed more light as to why valueChanges() did the trick and why do we need it?
@SaurabhRana you need it because you can't map over an AngularFireObject, instead, you need to map the Observable, that's why the valueChanges is needed here.
6

For RxJS 6 and later, you will need to import and use Observable, map, switchMap differently:

admin-auth-guard.service.ts:
import { Injectable } from '@angular/core';
import { map, switchMap } from 'rxjs/operators'
import { Observable } from 'rxjs';
import { UserService } from './user.service';
import { CanActivate } from '@angular/router';
import { AuthService } from './auth.service';

@Injectable({
  providedIn: 'root'
})
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

0

After Angular 9 and the typescript version, you need to modify code like this.

    //admin Guard
import { UserService } from './../Services/user.service';
import { AuthService } from './../Services/auth.service';
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
import { map, switchMap } from "rxjs/operators";

@Injectable({
  providedIn: 'root'
})
export class AdminGuard implements CanActivate {
  constructor(private authService: AuthService, private UserService: UserService) {

  }
  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

    return this.authService.userDetails$.pipe(switchMap(user => this.UserService.get(user!.uid).valueChanges()))
      .pipe(map(appUser => appUser!.isAdmin || false));

  }

}

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.