Je veux trier une liste de choses en fonction d'un champ observable, mais je ne peux pas comprendre les observables pour que cela fonctionne. Quelqu'un a-t-il une idée de comment y parvenir?
La situation initiale ressemble à ce qui suit:
Thing[] things;
interface Thing {
name: Observable<string>
}
<ul>
<li *ngFor="const thing for things">
{{thing.name | async}}
</li>
</ul>
De toute évidence, je n'ai pas bien décrit mon problème: le champ sur lequel je souhaite trier la liste des éléments est un observable, pas une chaîne simple. Je souhaite que le champ reste à jour via Websockets afin de pouvoir détecter correctement les modifications, je dois utiliser un champ Observable sur lequel je peux m'abonner.
Merci d'avoir clarifié la question, Phosphoros. :)
Voici comment vous pouvez faire ce que vous avez demandé:
// 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();
La journalisation des valeurs émises sur la console affiche un tableau d'objets Thing triés par leur propriété unwrappedName
:
[
{ id: 2, name: ScalarObservable, unwrappedName: "bar" },
{ id: 1, name: ScalarObservable, unwrappedName: "foo" },
{ id: 3, name: ScalarObservable, unwrappedName: "jazz" }
]
S'il vous plaît laissez-moi savoir si vous avez des questions sur ce code.
Si je vous comprends bien, vous voulez un objet qui ressemble à ceci:
Thing {
name: string;
}
Vous devez ensuite avoir un observable contenant un tableau de Thing
:
things$: Observable<Thing[]>;
Vous voulez ensuite trier vos objets dans le thing array
par une propriété, dans ce cas name
. Cela pourrait être fait comme ça:
...
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;
}
...
Et enfin, comme Toung Le a montré dans sa réponse, changez votre modèle comme ceci:
<ul>
<li *ngFor="let thing of sorted$ | async">
{{thing.name}} <!--No need async pipe here. -->
</li>
</ul>
Vous pouvez utiliser Observable.map
. Par exemple:
Observable<Thing[]> things;
sortedThings$ = things.map(items => items.sort()) // Use your own sort function here.
Dans votre modèle:
<ul>
<li *ngFor="let thing of sortedThings$ | async">
{{thing.name}} <!--No need async pipe here. -->
</li>
</ul>
Vous pouvez utiliser Observable.map
puis sort()
avec localeCompare
qui ressemblerait à ceci:
.map(data => ({
label: data.name
}))
.sort((a, b) => a.label.localeCompare(b.label));
Utilisez l'opérateur groupby
(jouez avec lui ):
const $things = getThings();
$things.pipe(
groupBy(thing => thing.id),
mergeMap(group$ => group$.pipe(
reduce((acc, cur) =>[...acc, cur], [])
))
)
.subscribe(console.log)