如何从订阅返回可观察

我试图返回一个可观察的时候,我得到了一个订阅者的某个值,但是我失败了。

这是密码:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<boolean> {
// get route to be activated
this.routeToActivate = route.routeConfig.path;


// get user access levels
return this._firebase.isUserAdmin          <-- returns Subscription, not Observable
.map(user => user.access_level)
.subscribe( access => {
// I need to return an observable here
});
}

在角度2的可观测物上没有太多的资源,所以我不知道从哪里开始。有人能帮忙吗?

更新-> 工作版本

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<boolean> {
// get route to be activated
this.routeToActivate = route.routeConfig.path;


// get user access levels
return this._firebase.isUserAdmin
.map(user => {
let accessLevel = user.access_level;


if (accessLevel === 'admin' ) {
return true;
}


}).first();
}
102720 次浏览

You can't return an observable from subscribe but if you use map instead of subscribe then an Observable is returned.

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<boolean> {
// get route to be activated
this.routeToActivate = route.routeConfig.path;


// get user access levels
return this._firebase.isUserAdminObservable
.map(user => {
// do something here
// user.access_level;
return true;
})
.first(); // for the observable to complete on the first event (usually required for `canActivate`)
// first needs to be imported like `map`, ...
}


canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<boolean> {
// get route to be activated
this.routeToActivate = route.routeConfig.path;


let subject = new Subject();
// get user access levels
this._firebase.isUserAdminObservable
.map(user => {
let accessLevel = user.access_level;
if (accessLevel === 'admin' ) {
subject.emit(true);
subject.complete();
}
return user;
});
return subject;
}

We can convert the Observable object to promise using toPromise method. so the code can be implemented as followed:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Promise<boolean> {
// get route to be activated
this.routeToActivate = route.routeConfig.path;


// get user access levels
return this._firebase.isUserAdmin
.map(user => {
return (user.access_level === 'admin');
}).toPromise();
}

You don't need map, code below specifies a predicate and a projection function for first.

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<boolean> {
this.routeToActivate = route.routeConfig.path;
return this._firebase.isUserAdminObservable
.first((_, index) => index === 0, user => {
// do something here
// user.access_level;
return true;
})
}

More on first

Couldn't we just use pipe with map from import { map } from 'rxjs/operators';?

import { map } from 'rxjs/operators';


@Injectable({
providedIn: 'root'
})
export class SearchHostService {
constructor(private readonly http: HttpClient) {}


searchForHosts(searchString: string): Observable<Employee[]> {
return this.http
.get<Employee[]>('./assets/host-users.json')
.pipe(
map(employees =>
employees.filter(({ displayName }) =>
displayName.toLowerCase().startsWith(searchString),
),
),
);
}
}

You can create a new observable, and fire the event according to the access level.

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<boolean> {
// get route to be activated
this.routeToActivate = route.routeConfig.path;


// get user access levels
return new Observable(subscriber=>{
this._firebase.isUserAdmin
.map(user => user.access_level)
.subscribe(access => {
// Return an observable!
// Change your logic here...
return access === XXX ? subscriber.next(true) : subscriber.next(false);
}, err => subscriber.error());
})
}

Reference: https://rxjs-dev.firebaseapp.com/guide/observable

Do this if you want to subscribe to observable, process the result and then return the same result in subscribe:

function xyx(): Observable<any> {
const response = someFunctionThatReturnsObservable().pipe(map(result => {
// here do any processing of the result //
return result; // return back same result.
}
))
return response;
}