Looking for better way to add page buttons to tables

Hi,

I am experimenting in this notebook with Inputs.table, and I added page buttons and a pagination function to show only a set number of rows (nrows) at a time so that the user doesn’t have to scroll down a huge page if the dataset is large. However, my solution requires the entire array to be passed to the table for page 1 and I wonder if there is a way around it.

If it’s the first page, the pagination function returns the entire array and the vertical scroll bar is disabled so that only the first nrows are displayed. This way, if the user then clicks on a column name to sort the data in that column, then the entire array of data will be sorted and the table will display the first nrows of the sort on page 1. Otherwise, if only the first nrows of data had been passed in to page 1, only that slice would be sorted.

If there was a way to access the click event on the table column, then the entire array could be sorted in whichever direction the user has clicked, and the correct slice corresponding to the page button the user is currently on when they clicked the column can be passed to the table.

Any comments or suggestions are welcome! Thank you

There’s no builtin way (see this issue). However, I’ve written a helper function that dispatches a sort CustomEvent when the sorting column or direction changes. You can find the helper here: Sortable Notebook List / Fabian Iwand / Observable

Example:

{
  const table = Inputs.table(data);
  pluginSortEvent(table);
  table.addEventListener('sort', e => {
    console.log(e.detail.sort, e.detail.reverse);
  });
}
1 Like

If you’re interested, there’s also a pager scheme that translates first/last/prev/next navigation to numeric indices:

image
image

You can find it here (might need to give the results a few seconds to load): Search Results Paging / Fabian Iwand / Observable

1 Like

Thanks @mootari !
I still cannot get around how to sort the full array but pass only a slice back to the table.

I can access the full data array in the event listener, and I can sort it according to the clicked column and direction, but I cannot return the desired slice it back to the table. For example, if reverse sort is true, the table will only show the reverse order of the input slice, and not the first slice of the full reverse-sorted array.

{
  // Initially, show first slice of data for page 1
  const table = Inputs.table(data.slice(pageLims[0], pageLims[1]));
  pluginSortEvent(table);
  table.addEventListener('sort', e => {
    console.log(e.detail.sort, e.detail.reverse);

   // Can sort the full `data` array here
  // How to return a slice of the full sorted data back to the table?
  });
}

Right, sorry. The table widget has no “offset” option which would be required for this kind of thing. You will have to presort your array, slice it and feed only the current range of entries to the table widget (i.e., reinstantiate it) along with the current sort column and order, and replace the old table.

Also consider any elements inside the table as off-limits, because you’ll likely get unexpected behavior when its lazy loading of rows kicks in.

Frankly, if you need a working paginated table then you may want to look into other table widgets (of which there are quite a few on Observable as well as on npm). However, if you’re only trying to see how far you can push Inputs.table(), then by all means keep at it! :smiley:

(You may also want to take a look at Input.table’s source to understand how and where your options are applied.)