Orderby with *ngFor array
Asked Answered
P

2

20

I made the following structure in my json file with Firebase Real Time Database to work on Composer and his Compositions:

enter image description here

I have the following service that give me the data of one composer with his composition

getComposerWithKey(key: string): Observable<Composer> {
const memberPath = `composer/${key}`;
this.composer = this.db.object(memberPath)
  .snapshotChanges().map(action => {
    const $key = action.payload.key;
    const arrcompositions = action.payload.val().compositions?Object.entries(action.payload.val().compositions):null;
    const data = { 
      $key,
      arrcompositions,
      ...action.payload.val() };
    return data;
  });
return this.composer
}

Now I can get the composer info with a list of his compositions with the ngFor directive :

<mat-list-item *ngFor="let composition of composer.arrcompositions">
    {{ composition[1] }}
</mat-list-item>

My problem is that I can't order the compositions in alphabetic order. I tried to use the ngx-order-pipe but I don't know how to precise the value used to order

<mat-list-item *ngFor="let composition of composer.arrcompositions | orderBy: 'composition[1]'">
{{ composition[1] }}

This obviously doesn't work...

Potts answered 23/1, 2018 at 13:39 Comment(0)
E
55

You should not use ordering pipes.

The Angular team and many experienced Angular developers strongly recommend moving to filter and sorting logic into the component.

If you want to sort your items by, let's say, name, here it goes :

sortBy(prop: string) {
  return this.composer.arrcompositions.sort((a, b) => a[prop] > b[prop] ? 1 : a[prop] === b[prop] ? 0 : -1);
}

In your HTML :

<mat-list-item *ngFor="let composition of sortBy('name')">
  {{ composition[1] }}
</mat-list-item>
Expellee answered 23/1, 2018 at 13:43 Comment(11)
thanks trichetriche for the advise I will stop using pipes for sorting items. I'm not sure I can use this filterBy function with my case as I'm working with key and value in my compositions node.Potts
key and value as in an object ? Because if so, your ngFor loop won't work !Expellee
my ngFor works because I creatan array with them : Object.entries(action.payload.val().compositions);Potts
And you want to sort an object properties?Expellee
yes I'm trying to sort them with the value (title of the compositions). I thought the structure node : [ composition : { name, compositions : { key1:value1, key2, value2, ....} } ] was the lighter one. And with this way, trying to work with denormalisation approach...Potts
If your data is repeated like this, you don't create an object, you create an array. Otherwise, you won't have any of the array functions, such as sorting, filtering, finding, reducing ... I highly advise you to change your model !Expellee
but with Object.entries it creates an array from the object with the key and value that I can call with composition[0] and composition[1]Potts
Up to you man, I'm just giving advice, not orders :) good luck with your project !Expellee
yeah I understand and makes me mad to transform my model again... but a little voice inside is telling me to follow your advice.... grrrrPotts
Very bad decision to use function instead of pure pipe... It could be not very critical if rendered content is simple, but for more complex layout it leads to perfomance issues that it's not easy to find. Why there are so many upvotes.. But idea of not using pipes and do sorting in code is nice, for example sort data after it loaded from server, or when some events occursGregoire
Your link is dead -- the page is still there but there's no longer a section about not using sort/filter pipes. I am also skeptical about calling a function inside the ngFor definition, because as I understand it that function will be called every time change detection runs. It would definitely be better if you could sort the collection, once, when it changes...Attainment
A
2

I use this package: ngx-pipes.

  • npm i ngx-pipes

import {NgPipesModule} from 'ngx-pipes';

@NgModule({
 // ...
 imports: [
   // ...
   NgPipesModule
 ]
})

<div *ngFor="let item of items | orderBy: 'id'"> {{ item }} </div>
Absorbefacient answered 25/1, 2022 at 12:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.