Как получить Observable <number>из операции сокращения для другой Observable в Nativescript Angular? - PullRequest
0 голосов
/ 15 ноября 2018

Я пытаюсь показать наблюдаемое всего в моем угловом компоненте, например:

total$ | async

Это должна быть сумма вычисления для всех строк в корзине покупок:

totalAmount = sum of (price * unitsOrdered)

Мои интерфейсы:

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

Мой угловой компонент содержит 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( ??? )
    );
}

Как я могу использовать функцию уменьшения, чтобы получить правильную сумму в моем представлении?

Обновление:

Это работает, однако:

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:

Этот код работает, когда я напрямую вызываю метод моего сервиса, который возвращает Observable of IBasket:

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

Этот код НЕ работает, когда я использую наблюдаемое из моего магазина:

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

Ответы [ 3 ]

0 голосов
/ 15 ноября 2018

Поскольку ваш map возвращает строки, и каждая строка будет содержать unitsOrdered и price, вы можете ввести еще один раунд 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
        )
    );
}

Вот вам Пример StackBlitz для вашей ссылки.

0 голосов
/ 15 ноября 2018

Я наконец-то нашел проблему сам. Это никак не связано с оператором Reduce. В тот момент, когда я выполнил функцию сокращения, данные для корзины еще не были получены из серверной части. Другими словами, хранилище еще не получило данные из моего действия LoadSuccess.
Поэтому я добавил новый селектор к моему редуктору для вычисления 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));
0 голосов
/ 15 ноября 2018
Функция

RxJs 'reduce работает аналогично функции Array.prototype.reduce.Вы даете ему функцию для обработки уменьшений и начального значения, и когда Observable завершается, тогда уменьшенное значение выводится из потока.Вот как вы можете рассчитать сумму:

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