web-dev-qa-db-de.com

Angular2 rxjs sortiert (beobachtbare) Liste von Objekten nach einem beobachtbaren Feld

Ich möchte eine Liste von Dingen nach einem beobachtbaren Feld sortieren, aber ich kann meinen Kopf nicht um Observables legen, damit das funktioniert. Hat jemand eine Idee, wie man das erreichen kann?

Die Ausgangssituation sieht ungefähr so ​​aus:

Thing[] things;

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

Da ich mein Problem offensichtlich nicht richtig beschrieben habe: Das Feld, in dem ich die Liste der Dinge sortieren möchte, ist ein Observable und keine einfache Zeichenfolge. Ich möchte das Feld über Websockets auf dem neuesten Stand halten, um die Änderungen richtig zu erkennen, muss ich ein Beobachtbares Feld verwenden, auf dem ich mich anmelden kann.

7
sclausen

Danke für die Klärung der Frage, Phosphoros. :)

So können Sie tun, was Sie gefragt haben:

// 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();

Bei der Protokollierung der ausgegebenen Werte in der Konsole wird ein Array von Thing-Objekten nach ihrer unwrappedName-Eigenschaft angezeigt:

[
  { id: 2, name: ScalarObservable, unwrappedName: "bar" },
  { id: 1, name: ScalarObservable, unwrappedName: "foo" },
  { id: 3, name: ScalarObservable, unwrappedName: "jazz" }
]

Bitte lassen Sie mich wissen, wenn Sie Fragen zu diesem Code haben.

13
AngularChef

Wenn ich Sie richtig verstehe, möchten Sie ein Objekt haben, das folgendermaßen aussieht:

Thing {
   name: string;
}

Sie möchten dann ein Observable haben, das für das Array von Thing gilt:

things$: Observable<Thing[]>;

Dann möchten Sie Ihre Dinge im thing array nach einer Eigenschaft sortieren, in diesem Fall name. Das könnte man so machen:

...

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

...

Und schließlich, wie Toung Le in seiner Antwort gezeigt, ändern Sie Ihre Vorlage folgendermaßen:

<ul>
  <li *ngFor="let thing of sorted$ | async">
    {{thing.name}} <!--No need async pipe here. -->
  </li>
</ul>
6
Fredrik Lundin

Sie können Observable.map verwenden. Zum Beispiel:

Observable<Thing[]> things;
sortedThings$ = things.map(items => items.sort()) // Use your own sort function here.

In Ihrer Vorlage:

<ul>
  <li *ngFor="let thing of sortedThings$ | async">
    {{thing.name}} <!--No need async pipe here. -->
  </li>
</ul>
3
Tuong Le

Sie können Observable.map und dann sort() mit localeCompare verwenden, was ungefähr so ​​aussehen würde:

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

Verwenden Sie den Operator groupby (play with ):

const $things = getThings();

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

Gruppevon Dokumenten .

0
Luillyfe