我想通过一个可观察的字段对事物列表进行排序,但不能围绕着可观察的事物来解决这个问题。有人知道如何实现这个目标吗?
最初的情况如下:
Thing[] things;
interface Thing {
name: Observable<string>
}
<ul>
<li *ngFor="const thing for things">
{{thing.name | async}}
</li>
</ul>
因为我显然没有正确地描述我的问题:我想要对事物列表进行排序的字段是Observable,而不是普通的字符串。我想通过websockets更新字段,以便正确检测更改我必须使用我可以订阅的Observable字段。
答案 0 :(得分:14)
感谢您澄清问题,Phosphoros。 :)
以下是你如何做你所问的:
// Function to compare two objects by comparing their `unwrappedName` property.
const compareFn = (a, b) => {
if (a.unwrappedName < b.unwrappedName)
return -1;
if (a.unwrappedName > b.unwrappedName)
return 1;
return 0;
};
// Array of Thing objects wrapped in an observable.
// NB. The `thing.name` property is itself an observable.
const thingsObs = Observable.from([
{ id: 1, name: Observable.of('foo') },
{ id: 2, name: Observable.of('bar') },
{ id: 3, name: Observable.of('jazz') }
]);
// Now transform and subscribe to the observable.
thingsObs
// Unwrap `thing.name` for each object and store it under `thing.unwrappedName`.
.mergeMap(thing =>
thing.name.map(unwrappedName => Object.assign(thing, {unwrappedName: unwrappedName}))
)
// Gather all things in a SINGLE array to sort them.
.toArray()
// Sort the array of things by `unwrappedName`.
.map(things => things.sort(compareFn))
.subscribe();
将发出的值记录到控制台将显示按其unwrappedName
属性排序的Thing对象数组:
[
{ id: 2, name: ScalarObservable, unwrappedName: "bar" },
{ id: 1, name: ScalarObservable, unwrappedName: "foo" },
{ id: 3, name: ScalarObservable, unwrappedName: "jazz" }
]
如果您对此代码有疑问,请与我们联系。
答案 1 :(得分:7)
如果我理解正确,你想要一个看起来像这样的对象:
Thing {
name: string;
}
然后你想拥有一个支持Thing
数组的Observable:
things$: Observable<Thing[]>;
然后,您希望通过属性thing array
对事物进行排序,在本例中为name
。这可以这样做:
...
let sorted$: Observable<Thing[]> = things$.map(items => items.sort(this.sortByName))
...
sortByName(a,b) {
if (a.name < b.name)
return -1;
if (a.name > b.name)
return 1;
return 0;
}
...
最后,就像 Toung Le 在他的回答中所示,更改你的模板:
<ul>
<li *ngFor="let thing of sorted$ | async">
{{thing.name}} <!--No need async pipe here. -->
</li>
</ul>
答案 2 :(得分:3)
您可以使用Observable.map
。例如:
Observable<Thing[]> things;
sortedThings$ = things.map(items => items.sort()) // Use your own sort function here.
在你的模板中:
<ul>
<li *ngFor="let thing of sortedThings$ | async">
{{thing.name}} <!--No need async pipe here. -->
</li>
</ul>
答案 3 :(得分:2)
您可以在Observable.map
中使用sort()
然后将localeCompare
与.map(data => ({
label: data.name
}))
.sort((a, b) => a.label.localeCompare(b.label));
一起使用:
^
答案 4 :(得分:0)
使用groupby
运算符(播放with it):
const $things = getThings();
$things.pipe(
groupBy(thing => thing.id),
mergeMap(group$ => group$.pipe(
reduce((acc, cur) =>[...acc, cur], [])
))
)
.subscribe(console.log)
答案 5 :(得分:0)
了解了.pipe
的工作原理和其中的Operators后,这是一个非常简单的解决方案。
如果我们使用toArray
运算符将所有项目转换为数组,然后将整个数组作为单个项目通过管道传递给mergeMap
运算符,则可以对其进行排序,然后分解出该数组回来。
interface Thing {
name: string;
}
const things: Observable<Thing>;
...
things
.pipe(toArray())
.pipe(mergeMap(_things =>
_things.sort((a, b) =>
a.name.localeCompare(b.name)
)
));
// OR
things.pipe(toArray(), mergeMap(_things =>
_things.sort((a, b) =>
a.name.localeCompare(b.name)
)
));
答案 6 :(得分:0)
使用过滤功能更改排序功能也使其适用于 rxjs 6.6.2