Skip to content

Paginated Query

For paginated queries, you only need the queryById utilities. You may also use the insertPaginationPlaceholderData that will display the previous page data during the new page loading. See more about insertions in insertions section.

Simple Example

ts
const userListStore = signalStore(
  withProps(() => ({
    api: inject(ApiService),
  })),
  withState({
    page: 1,
  }),
  withQueryById('users', (store) =>
    rxQueryById(
      {
        params: store.page,
        identifier: (params) => params,
        stream: ({ params: page }) =>
          store.api.getDataList$({
            page: page,
            pageSize: 4,
          }),
      },
      // 👇 Use it to display the previous page data during the incoming page loading
      // It also expose currentPageData / currentPageStatus / isPlaceholderData
      insertPaginationPlaceholderData
    )
  ),
  withMethods((store) => ({
    nextPage: () =>
      patchState(store, (state) => ({
        page: state.page + 1,
      })),
    previousPage: () =>
      patchState(store, (state) => ({
        page: state.page - 1,
      })),
  }))
);

// usage
userListServerStateStore2.usersQueryById.currentPageData; // Signal<User[] | undefined>

Advanced pagination

In the simple example, the list is only drive by the page number, no sorting, no custom page size... But when adding sorting, custom page size... their is more works todo and it is not straightforward.

This project is new, but maybe an insertion can help to simplify this case. Let me know if you have interesting ideas

For this advanced pagination, we will make example based on this pagination state:

ts
// ...
const advancedPaginationStore = signalStore(
  withState({
    pagination: {
      page: 1,
      pageSize: 4,
    },
  }),
  withQueryById('users', (store) =>
    queryById(
      {
        params: store.pagination,
        // ...
      },
      insertPaginationPlaceholderData
    )
  )
  // ...
);

Their is two way, I think to deal with advanced pagination.

WARNING

  • Make sur to understand the link between the params and the identifier, that will generate the pagination Map key(generated by the identifier)/pageValue (that is a represented by a resource).
  • And the equalParams option.

Case one: Handle it with equalParams

ts
const advancedPaginationStore = signalStore(
  withState({
    pagination: {
      page: 1,
      pageSize: 4,
    },
  }),
  withQueryById('users', (store) =>
    queryById(
      {
        params: store.pagination,
        identifier: (params) => params.page,
        equalParams: (a, b) => a.page === b.page && a.pageSize === b.pageSize,
        // ...
      },
      insertPaginationPlaceholderData
    )
  )
  // ...
);

Here what is does:

  • The identifier: (params) => params.page, will index all the pages value by the page number : Map<PageNumber, PageValue>
  • The equalParams: (a, b) => a.page === b.page && a.pageSize === b.pageSize will be used when accessing to the current page resource as equal parameter.

Why using the equalParams ?

  • Each page value is represented by a resource, of which the params is the global params du queryById => params: store.pagination,.
  • Now, imagine you change to the next page, then go back to the previous page.
  • The global params will be: {page: 1, pageSize: 4} / {page: 2, pageSize: 4} / {page: 1, pageSize: 4}
  • But each time the page change, the reference will surely change, that means the corresponding resource will load again, whereas the resource params are equals.
  • This is why equalParams can be useful, to only reload an existing page if the params really change

Case two: Advanced identifier

To solve the same problem (avoiding to reload the same page when the pagination values are the same), it is possible to use a custom identifier.

ts
const advancedPaginationStore = signalStore(
  withState({
    pagination: {
      page: 1,
      pageSize: 4,
    },
  }),
  withQueryById('users', (store) =>
    queryById(
      {
        params: store.pagination,
        identifier: (params) => `${params.page}-${params.pageSize}`,
        // ...
      },
      insertPaginationPlaceholderData
    )
  )
  // ...
);

Here what is does:

  • Will generate a new resource with associated his custom identifier for each pagination combination

Example

Check the List with pagination example in the examples section