Akita: Allowing different sorting strategies based on state

Created on 12 Sep 2018  路  12Comments  路  Source: datorama/akita

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report  
[ ] Performance issue
[X] Feature request
[ ] Documentation issue or request
[ ] Support request
[ ] Other... Please describe:

Current behavior


Currently, you can configure how to sort your data by providing a sort function either in the @QueryConfig or in select query options.
That's awesome, but what if there is a case when you'd want to provide a custom sorting logic based on state. An API that would allow this would look something like this:

const sortBy: SortBy<CategoriesState, ICategory> =
   (state) => (a, b) => state.sortByOrderNum ? (a.orderNum - b.orderNum) : a.name.localeCompare(b.name);
@QueryConfig({ sortBy })

Unfortunatelly I don't see how such change could be made via a non-breaking change as it's changing the SortBy interface.

What is the motivation / use case for changing the behavior?


Make Akita more flexible

enhancement

All 12 comments

I'm looking into the same topic, and just curious what you all think about sorting the Observable after the state has been broadcasted? For example suppose we get an observable of Todo instances from the store (Pseudo code):

let todos$ = store.observe();
todos$.toArray().map(arr=>arr.sort(comparator)).subscribe(sorted=>this.todos=sorted);

The component would then render the todos array directly instead of rendering the $todos observable via an async pipe.

Initially, that's almost exactly how I implemented this logic. Except that this logic was inside a custom query method (because I like my components slim):

@Injectable({ providedIn: 'root' })
export class CategoriesQuery extends QueryEntity<CategoriesState, ICategory> {
  constructor(
    protected store: CategoriesStore,
    private itemsQuery: ItemsQuery
  ) {
    super(store);
  }

  selectCategories() {
    return return combineLatest(
      this.selectAll(),
      this.select(s => s.ui.isCustomSort)
    ).pipe(([categories, isCustomSort]) => {
      if(isCustomSort) {
        categories.sort(mySortingFunction)
      }
      return categories;
    })
  }
}

but then I found out about sortBy option and though that using it would reduce quite a lot of builerplate - this whole method I wrote above would go away. If only it allowed access to the state...

Good point. Something like:

let todos$ = store.observeSorted(comparator);

Would be a lot shorter.

@DmitryEfimenko we can extend the signature of the SortBy function and don't introduce a breaking change.

export type SortBy = ((a: E, b: E, state?: S) => number) | keyof E;

you're right.
In this case it looks like the signature of toArray function will change to take entire state instead of ids: ID[], entities: HashMap<E>. Does that sound right to you, @NetanelBasal ?

I could take a stab at this if you do not have objections.

Yes, that's okay, it's internal method. You can create a PR, thanks.

:tada: This issue has been resolved in version 1.9.0 :tada:

The release is available on npm package (@latest dist-tag)

Your semantic-release bot :package::rocket:

@NetanelBasal Can I get a 馃 badge? :)

I think it's badge worthy.

@DmitryEfimenko Of course, which badge?

The badge that goes in under the Contributor name on this page. It's titled "Ideas, Planning, & Feedback". It looks like 馃.

No problem.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Tobjoern picture Tobjoern  路  3Comments

zvnt picture zvnt  路  6Comments

stephencarr picture stephencarr  路  4Comments

DmitryEfimenko picture DmitryEfimenko  路  6Comments

brgrz picture brgrz  路  4Comments