【问题标题】:How to get an Observable<number> from a reduce operation on another Observable in Nativescript Angular?如何从 Nativescript Angular 中另一个 Observable 的 reduce 操作中获取 Observable<number>?
【发布时间】:2018-11-16 03:22:32
【问题描述】:

我试图在我的角度组件中显示一个可观察的 total,如下所示:

total$ | async

它应该是购物篮中所有行的计算总和:

totalAmount = sum of (price * unitsOrdered)

我的界面是:

export interface IBasketLine {
    unitsOrdered?: number;
    price?: number;
}
export interface IBasket {
    header?: IBasketHeader;
    lines?: Array<IBasketLine>;
}

我的 Angular 组件包含 2 个可观察对象

basket$: Observable<IBasket>;
nettoTotal$: Observable<number>;

可观察的购物篮$ 是从我的 ngrx 存储中初始化的,并且所有行在我的视图中都是可见的。这是我的 ngOnInit 函数:

ngOnInit(): void {

   this.store.dispatch(new basketActions.Load());

    this.basket$ = this.store.pipe(
        select(fromBasket.getBasket)
    );

    this.nettoTotal$ = this.basket$.pipe(
        map((basket) => basket.lines),
        reduce( ??? )
    );
}

如何使用 reduce 函数,以便在我的视图中获得正确的总数?

更新:

这确实有效:

this.nettoTotal$ = this.basket$.pipe(
  map((basket) => {
     if (basket) {
        return basket.lines;
     } else {
        return [];
     }
  }),
  map((lines) => {
            let total = 0;
            for (const line of lines) {
                const val = Math.round((line.bestelaantal * line.nettoprijs * 100) / 100);
                total = total + val;
            }

            return total;
        })
    );

更新 2:

当我直接调用返回 IBasket 的 Observable 的服务方法时,此代码有效:

this.nettoTotal$ = this.basketService.getBasket().pipe(
            map((basket) => basket.lines),
            map((lines) => lines.map((line) => line.nettoprijs * line.bestelaantal).reduce(
                (accumulator, linePrice) => accumulator + linePrice,
                0
            ))
        );

当我使用来自我的商店的 observable 时,此代码不起作用:

this.nettoTotal$ = this.basket$.pipe(
            map((basket) => basket.lines),
            map((lines) => lines.map((line) => line.nettoprijs * line.bestelaantal).reduce(
                (accumulator, linePrice) => accumulator + linePrice,
                0
            ))
        );

【问题讨论】:

  • 在这种情况下,尝试 subscribebasket$ Observable 并将响应记录到控制台以检查究竟是什么错误。

标签: angular typescript reduce


【解决方案1】:

RxJs 的 reduce 函数的工作方式类似于 Array.prototype.reduce 函数。你给它一个处理 reduce 和种子值的函数,当 Observable 完成时,从流中发出减少的值。以下是计算总和的方法:

this.nettoTotal$ = this.basket$.pipe(
  map((basket) => basket.lines),
  reduce((total, count) => total + count, 0)
);

【讨论】:

    【解决方案2】:

    由于您的map 正在返回行并且每行将包含unitsOrderedprice,因此您可以引入另一轮map 并直接从那里返回price * unitsOrdered,然后将其累积在reduce 运算符中。

    试试这个:

    ngOnInit(): void {
    
       this.store.dispatch(new basketActions.Load());
    
        this.basket$ = this.store.pipe(
            select(fromBasket.getBasket)
        );
    
        this.nettoTotal$ = this.basket$.pipe(
            map(basket => basket.lines),
            map(lines => lines.map(line => line.price * line.unitsOrdered)),
            reduce(
              (accumulator, linePrice) => accumulator + linePrice,
              0
            )
        );
    }
    

    这里有一个Sample StackBlitz 供您参考。

    【讨论】:

    • 感谢您的回复。我试过了,但没有给出总数。
    • @pdw,你有什么错误吗?我刚刚注意到line.unitsOrdered 之间有一个空格。我已经修好了。请再次检查并让我知道这是否有效。如果它仍然不起作用,请告诉我你在subscribeing 到Observable 上的具体内容,或者你是否遇到任何错误。
    • 我没有收到任何错误。屏幕上的总数只是空白。但是,我只在我的视图中使用异步管道订阅。我用有效的代码更新了我的问题。
    • 你能用最少的可复制代码示例在 StackBlitz 上复制它吗?
    • 这对我来说很难。我在 ios 模拟器上使用 Nativescript 和 Angular,我之前从未使用过 Stackblitz。
    【解决方案3】:

    我自己终于找到了问题所在。它与 reduce 运算符完全无关。在我执行 reduce 函数的那一刻,篮子的数据还没有从后端获取。换句话说,商店还没有从我的 LoadSuccess 操作中收到数据。
    所以我最终在我的 reducer 中添加了一个新的选择器来计算 netTotal。

    export const getNetTotal = createSelector(
        getBasketFeatureState,
        (state) => {
            if (!state.basket) {
                return 0;
            }
            let total = state.basket.lines.map((line) => (line.amountOrdered * line.price)).reduce(
                (total, amount) => total + amount,
                0
            );
            total = Math.round(total * 100) / 100;
    
            return total;
        }
    );
    

    ngOnInit 函数现在看起来像这样,一切正常:

    this.store.dispatch(new basketActions.Load());
    
    this.basket$ = this.store.pipe(select(fromBasket.getBasket));
    this.nettoTotal$ = this.store.pipe(select(fromBasket.getNetTotal));
    

    【讨论】:

      猜你喜欢
      • 2020-12-19
      • 2021-12-20
      • 2018-07-15
      • 2018-08-04
      • 2020-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多