【问题标题】:Looking for something like OrElse in angular rxjs find function while piping在 angular rxjs 中寻找类似 OrElse 的东西在管道中查找函数
【发布时间】:2020-02-29 18:16:01
【问题描述】:

我有以下代码。我想要实现的是当“查找”功能在可观察的加载订单中找不到任何订单对象时重定向到找不到的页面。

private order: Observable<OrderModel>;

ngOnInit() {
    this.route.params.subscribe(params => {
    this.name = params.id;
    this.order = this.orderService.ordersLoaded.pipe(map((orders: OrderModel[]) => orders
          .find((order: OrderModel) => order.orderName === this.name.toUpperCase())));
 });

我尝试过类似的方法:

ngOnInit() {
    this.route.params.subscribe(params => {
    this.name = params.id;
    this.order = this.orderService.ordersLoaded.pipe(map((orders: OrderModel[]) => orders
        .find((order: OrderModel) => order.orderName === this.name.toUpperCase()),
        defaultIfEmpty(this.router.navigate(['/notFound']))
      ));
 });

但它总是将我重定向到未找到的页面组件。

【问题讨论】:

    标签: javascript angular typescript rxjs angular8


    【解决方案1】:

    您可以点按运算符来归档您想要的内容:

    this.order = this.orderService.ordersLoaded.pipe(
          map((orders: OrderModel[]) => orders.find(order => order.orderName === this.name.toUpperCase()),
          tap(order => {
            if (!order) {
              this.router.navigate(['/notFound']);
            }
          })
        ));
    

    你可以创建一些自定义的 rxjs 操作符来摆脱if

    export function tapIf<T>(
      predicate: (value: T) => boolean,
      fn: (x: T) => void
    ): MonoTypeOperatorFunction<T> {
      return input$ =>
        input$.pipe(
          tap(x => {
            if (predicate(x)) {
              fn(x);
            }
          })
        );
    }
    
    export function tapIfFalsy<T>(fn: (x: T) => void): MonoTypeOperatorFunction<T> {
      return tapIf<T>(x => !x, x => fn(x));
    }
    

    那么你的代码可以变得更加简单:

    this.order = this.orderService.ordersLoaded.pipe(
          map((orders: OrderModel[]) => orders.find(order => order.orderName === this.name.toUpperCase()),
          tapIfFalsy(() => this.router.navigate(['/notFound']))
        ));
    

    【讨论】:

      【解决方案2】:

      defaultIfEmpty() 实际上只在 observable 完成但没有返回任何内容时触发, https://www.learnrxjs.io/operators/conditional/defaultifempty.html 它与返回的值无关

      你可以试试下面的代码

      zip(this.orderService.ordersLoaded,this.route.params).pipe(tap([orders,params])=>{
        this.name = params.id;
        if(!orders.find(order=>order.orderName === this.name.toUpperCase())
              this.router.navigate(['/notFound'])
      }).subscribe()
      

      【讨论】:

      • 不要使用 zip,如果需要,它不会发出第二个值。
      • 是的,但是上面的代码会发出,即使http超时也会发出错误
      • 有组合 latest\forkjoin 运算符。在这种情况下,Zip 是完全不可接受的。如果您在更改路由器参数的情况下停留在同一个组件上,您将不会重新获取上面的代码
      • 如果是连续流,那么我们改回switchMap方法更有意义
      • 我的意思是使用 zip 没有任何意义,因为它不会添加任何有用的行为,并且如果更改逻辑可能会导致不希望的事情。
      猜你喜欢
      • 2019-07-24
      • 2010-12-07
      • 2016-02-15
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多