RxJS 6 filter and map an observable array of items

Jan Nielsen

In my Angular 7.1.1 application with RxJS 6.3.3, an observable array of plans should be transformed into an observable array of active plan cards. The active filter is:

filter(plan => plan.is_active)

and the transformation of plan to card is:

map(plan => new PlanCard(plan, 1, 1))

so, presumable, the answer is something like:

plans: Observable<Plan[]> = getPlans();

cards: Observable<PlanCard[]> = plans.pipe(
  mergeAll(),
  filter(plan => plan.is_active),
  map(plan => new PlanCard(plan, 1, 1)),
  toArray()
);

But alas, cards is empty.

The plans can correctly be transformed to cards via:

cards: Observable<PlanCard[]> = plans.pipe(
  map(plans => plans.map(plan => new PlanCard(plan, 1, 1)))
);

but adding a filter prior does not filter the plans, unfortunately:

cards: Observable<PlanCard[]> = plans.pipe(
  filter(plans => plans.filter(plan => plan.is_active)),
  map(plans => plans.map(plan => new PlanCard(plan, 1, 1)))
);

Any better ideas?

export const planData: Plan[] = [{
  name: 'P1',
  is_active: true
}, {
  name: 'P2',
  is_active: true
}, {
  name: 'P3',
  is_active: true
}, {
  name: 'P4',
  is_active: true
}, {
  name: 'P5',
  is_active: false
}];

export const plans = createObservable(planData);
Adrian Brand

mergeAll merges an observable of observables.

You want

cards: Observable<PlanCard[]> = plans.pipe(
  map(plans => plans.filter(plan => plan.is_active)), // An array comes down the pipe, you don't want to filter out the arrays but the elements in the array
  map(plans => plans.map(plan => new PlanCard(plan, 1, 1))), // An array of active plans can be mapped into an array of PlanCards
  reduce((results, plans) => [...results, ...plans], []) // Reduce all the arrays into a single array
);

You can use scan instead of reduce if you want the accumulator of the reduce to come down the pipe each time a new array comes down, reduce only fires after all arrays have come down the pipe.

I don't usually use a filter followed by a map but it is easier to see what is going on, I would usually do it in a single step with a reduce,

plans => plans.reduce((results, plan) => plan.is_active ? [...results, new PlanCard(plan, 1, 1)] : results, [])

Is the same as a filter followed by a map but does it in a single iteration instead of two.

It can be quite confusing when you have observables of arrays, you need to consider what functions you want to apply to the observable and which you want to apply to the array that comes down the pipe.

const { from } = rxjs;
const { map, reduce } = rxjs.operators;

const plans = from([
  [{id: 1, is_active: true}, {id: 2, is_active: false}, {id: 3, is_active: true}, {id: 4, is_active: true}],
  [{id: 5, is_active: true}, {id: 6, is_active: true}],
  [{id: 7, is_active: false}, {id: 8, is_active: true}, {id: 9, is_active: true}],
  [{id: 10, is_active: true}, {id: 11, is_active: false}, {id: 12, is_active: true}, {id: 13, is_active: false}],
]);

function PlanCard(plan) {
  this.id = plan.id;
}

plans.pipe(
  map(plans => plans.reduce((results, plan) => plan.is_active ? [...results, new PlanCard(plan, 1, 1)] : results, [])),
  reduce((results, plans) => [...results, ...plans], [])
).subscribe(results => { console.log(results); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.3.3/rxjs.umd.min.js"></script>

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

RxJs how to map the items in an Observable<Array>

rxjs6 filter Observable<Array<any>>

Simple filter on array of RXJS Observable

rxjs Filter an array of objects observable

Angular RxJS Observable Filter on array of objects

Observable of array with filter using Angular 5 with RxJS

RxJS 6 get a filtered list of array of Observable

Rxjs6 - filter array of objects

Observable rxjs filter

Update Rxjs observable of array by adding ,filtering or deleting items

How to get an Observable to return an array of transformed items (Rxjs)

RxJS Map array to observable and back to plain object in array

Angular 6 - rxjs property 'map' does not exist on type 'observable'

Property 'map' does not exist on type 'Observable' after upgrading rxjs to 6

rxjs Observable .map not executing

Javascript map then filter unique array items

RxJs Array of Observable to Array

Observable of array to array (Rxjs)

Angular & Rxjs: How to map json to object array in a function returning Observable

RxJs Observable in Observable from Array

Map array and include items according to ID using MAP and FILTER

How filter a json with observable rxJS

How to throwError within map of observable (rxjs6, ng6)

Rxjs: map each element in an array field from an observable of object with another observable

rxjs how to pass observable to map

How to type array map arguments from rxjs 6 withLatestFrom

How to use rxjs map to filter out an observable list of object by another list of objects of different type

How to get items with approved ids from another array? map() filter() or?

RxJS Filter Array of Arrays