[英]RxJS 6 filter and map an observable array of items
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.在我的带有 RxJS 6.3.3 的 Angular 7.1.1 应用程序中,一个可观察的计划数组应该转换为一个可观察的活动计划卡片数组。 The active filter is:
有源滤波器是:
filter(plan => plan.is_active)
and the transformation of plan to card is: plan 到 card 的转换是:
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.但是,唉,
cards
是空的。
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);
mergeAll merges an observable of observables. mergeAll 合并一个 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.如果您希望 reduce 的累加器在每次新阵列下降时从管道下降,则可以使用扫描而不是 reduce,只有在所有阵列下降到管道后才减少触发。
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,我通常不使用过滤器后跟地图,但更容易看到发生了什么,我通常会在一个步骤中使用 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>
This had me scratching my head for a while, so a brief example which may be of help if you're looking to filter an observable array of objects.这让我摸不着头脑了一会儿,所以如果你想过滤一个可观察的对象数组,那么一个简短的例子可能会有所帮助。 Kudos to @ Adrian for pointing me in the right direction.
感谢@Adrian为我指明了正确的方向。
If you have a service that returns an observable array of objects, eg:如果您有一个返回可观察对象数组的服务,例如:
dataSub = new BehaviorSubject<Array<object>>([]);
getItems(): Observable<Array<object>> {
return this.dataSub.asObservable();
}
You can filter with a given criteria with the following.您可以使用以下给定条件进行过滤。 In this example, I want only elements where the property 'selected' is true.
在此示例中,我只需要属性“selected”为 true 的元素。
constructor() {
this.getItems()
.pipe(
map(items => items), /* Don't forget to add this! */
filter(item => item['selected'] === true)
)
.subscribe(data => {
console.log(data);
});
}
The (rookie) error which led to my confusion was omitting the 'map', so the filter function was being applied to the whole array, rather than each element.导致我困惑的(菜鸟)错误是省略了“地图”,因此过滤器功能被应用于整个数组,而不是每个元素。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.