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.
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.
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>
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>
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));
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)