Angular2 rxjs 按可观察字段对对象列表进行排序(可观察)



我想按可观察字段对事物列表进行排序,但无法围绕可观察量来使其工作。有人知道如何实现这一目标吗?

初始情况如下所示:

Thing[] things;
interface Thing {
  name: Observable<string>
}
<ul>
  <li *ngFor="const thing for things">
    {{thing.name | async}}
  </li>
</ul>

因为我显然没有正确描述我的问题:我想对事物列表进行排序的字段是可观察的,而不是普通的字符串。我想通过 websocket 保持字段更新,以便正确检测更改,我必须使用我可以订阅的可观察字段。

感谢您澄清这个问题,磷。 :)

以下是您如何按照您的要求进行操作:

// 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" }
]

如果您对此代码有疑问,请告诉我。

如果我理解正确,您希望有一个看起来像这样的对象:

Thing {
   name: string;
}

然后,您需要一个保存Thing数组的可观察量:

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>
您可以使用

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>

>您可以使用Observable.map然后与localeCompare一起sort()

,如下所示:
.map(data => ({
        label: data.name
}))
.sort((a, b) => a.label.localeCompare(b.label));
这是一个

非常简单的解决方案,一旦您了解.pipe的工作原理以及存在哪些运算符。

如果我们使用运算符将所有项目转换为数组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)
   )
));

使用groupby运算符(使用它(:

const $things = getThings();
$things.pipe(
    groupBy(thing => thing.id),
    mergeMap(group$ => group$.pipe(
        reduce((acc, cur) =>[...acc, cur], [])
    ))
)
.subscribe(console.log)

分组依据文档。

使用过滤器函数更改了排序功能,使其也适用于 rxjs 6.6.2

https://stackblitz.com/edit/rxjs-ys7a9m?file=index.ts

最新更新