【问题标题】:How to return observable from subscribe如何从订阅中返回 observable
【发布时间】:2017-02-17 13:03:05
【问题描述】:

当我在订阅者中获得某个值时,我试图返回一个 observable,但我失败了。

这是代码:

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

【问题讨论】:

  • 你应该在 rxjs 而不是 ng2 中搜索 Observables。有大量的资源
  • 谢谢!我试过了,但它们的格式与 Angular 2 使用的格式不同。我想我必须从头开始学习。
  • 你能进一步解释这段代码的上下文吗?由于subscribe 返回Subscription 对象以取消订阅,因此不可链接,通常你想做observable.subscribe(...); return observable
  • Angular 使用 rxjs5。许多资源都是关于 rxjs4 的。我想这就是你所说的“不要采用相同的格式”(github.com/ReactiveX/rxjs == V5 vs github.com/Reactive-Extensions/RxJS == V4)

标签: angular typescript rxjs observable


【解决方案1】:

您不能从 subscribe 返回 observable,但如果您使用 map 而不是 subscribe,则会返回 Observable

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

【讨论】:

  • 您好,感谢您的回答!我需要根据值在 subscribe 内部进行一些处理,然后返回 true|false
  • 就是这样。现在没有错误,但是路由仍然没有解锁,尽管它发送的是 true。我会尝试摆弄它并让它工作,也许我会在这个过程中学到一些东西。非常感谢!
  • 抱歉,我的意思是 map 函数似乎采用了一个 lambda,它可以访问其范围之外的变量。但我想这就是 lambdas 可以做的——这让我有点吃惊。不过,解决了我的问题!
  • @anytoe 对,没有办法阻止这种情况。你自己处理好了。
  • @GünterZöchbauer,您能否更新答案以包含RxJS 6.0 代码?
【解决方案2】:

难道我们不能将pipeimport { map } from 'rxjs/operators'; 中的map 一起使用吗?

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 而是一个不同的值呢?最初的问题是调用获取 Observable 但他想返回 Observable 的代码
【解决方案3】:

如果要订阅 observable,请执行此操作,处理结果,然后在订阅中返回相同的结果:

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

【讨论】:

    【解决方案4】:

    我们可以使用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();
        }
    

    【讨论】:

      【解决方案5】:

      你不需要map,下面的代码为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

      【讨论】:

        【解决方案6】:

        您可以创建一个新的 observable,并根据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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-03-26
          • 2019-03-09
          • 1970-01-01
          • 2018-09-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多