如何从subscribe返回observable

93

我试图在订阅器中获取特定值时返回一个可观测对象,但是我失败了。

这是代码:

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
        });
}
在 Angular 2 中关于 observables 的资源并不多,所以我不知道从哪里开始。有人可以帮忙吗? 更新-> 工作版本
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();
        }

1
你应该在 rxjs 中搜索 Observable,而不是 ng2。这里有大量的资源可供参考。 - drew moore
谢谢!我尝试了一下,但它们没有使用 Angular 2 相同的格式。我想我只能从头开始学习了。 - Dragos Ionescu
你能进一步解释一下这段代码的上下文吗?由于subscribe返回一个Subscription对象以取消订阅,因此不可链接,通常你会想要执行observable.subscribe(...); return observable - Estus Flask
3
Angular使用rxjs5。许多资源都是关于rxjs4的。我猜这就是你所说的“格式不同”的意思(https://github.com/ReactiveX/rxjs == V5 vs https://github.com/Reactive-Extensions/RxJS == V4) 。 - Günter Zöchbauer
6个回答

105

如果你使用 map 而不是 subscribe,那么可以返回一个 Observable,但是不能从 subscribe 中返回一个可观测对象。

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

你也可以在 map 中这样做,只需将 user.access_level 更改为 {user.access_level; ...},并且您可以像普通函数一样添加多个语句。确保在最后返回结果,否则接收方将不会收到任何内容。 - Günter Zöchbauer
1
就是这样。现在没有错误了,但路线仍然没有解锁,尽管它发送的是true。我会试着调整一下并让它工作,也许在这个过程中我会学到一些东西。非常感谢! - Dragos Ionescu
1
抱歉,我是说map函数似乎接受一个能够访问其外部作用域变量的lambda表达式。但我猜这就是lambda的特性 - 这有点让我惊讶。不过,问题已经解决了! - Anytoe
1
@anytoe 对,没有办法防止这种情况。你必须自己注意处理。 - Günter Zöchbauer
4
@GünterZöchbauer,请您更新答案以包含 RxJS 6.0 代码? - th1rdey3
显示剩余10条评论

12

如果您想订阅Observable并处理结果,然后在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;
}

11

我们不能只使用来自import { map } from'rxjs/operators';mappipe吗?

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

但是如果我们不返回Observable<Employee>而是其他值呢?原始问题调用获取Observable<User>的代码,但他想要返回Observable<bool>。 - Rhyous

6
我们可以使用toPromise方法将Observable对象转换为Promise。 因此代码可以实现如下:
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();
    }

2
你不需要使用map函数,下面的代码指定了一个谓词和一个投影函数来获取第一个元素。
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;
         })
}

了解更多关于 first 的内容


0
你可以创建一个新的可观察对象,并根据access级别触发事件。
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());
    })
}

参考资料:https://rxjs-dev.firebaseapp.com/guide/observable


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接