簡體   English   中英

Angular2 rxjs 按可觀察字段排序(可觀察)對象列表

[英]Angular2 rxjs sort (observable) list of objects by an observable field

我想按可觀察字段對事物列表進行排序,但無法圍繞可觀察對象進行排序以使其正常工作。 有人知道如何實現這一目標嗎?

初始情況類似於以下內容:

Thing[] things;

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

因為我顯然沒有正確描述我的問題:我想要對事物列表進行排序的字段是一個 Observable,而不是一個普通的字符串。 我想通過 websockets 保持該字段的更新,以便正確檢測更改,我必須使用我可以訂閱的 Observable 字段。

感謝您澄清問題,磷。 :)

以下是您可以按照您的要求執行的操作:

// 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;
}

然后,您需要一個 Observable 來保存Thing數組:

things$: Observable<Thing[]>;

然后,您希望通過屬性(在本例中為namething array中的thing array進行排序。 可以這樣做:

...

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然后sort()localeCompare ,它看起來像這樣:

.map(data => ({
        label: data.name
}))
.sort((a, b) => a.label.localeCompare(b.label));

使用groupby運算符(使用它):

const $things = getThings();

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

Groupby 文檔

這是一個非常簡單的解決方案,一旦您了解.pipe工作原理以及那里有哪些Operator

如果我們使用toArray運算符將所有項目轉換為數組,並將整個數組作為單個項目通過mergeMapmergeMap運算符,我們將能夠對其進行排序,然后將數組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)
   )
));

使用過濾功能更改了排序功能也使其適用於 rxjs 6.6.2

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM