Code

js/views/collection.js — the table and pagination

In the code column — js/views/collection.js. renderCollection() gets an already sorted and filtered list from getFilteredFavorites(), works out the pages, and slices out the current one.

The pagination maths is three lines:

const totalPages = Math.max(1, Math.ceil(rows.length / pageSize));
const page = Math.min(currentPage, totalPages);          // guard: page may be stale
const pageRows = rows.slice(start, start + pageSize);

Math.min(currentPage, totalPages) matters: if you were on page 5 and a search leaves only 2 pages, currentPage would still be 5 and the table would be empty. We "clamp" it to the real maximum.

The sort headers and initCollection are the delegation pattern again (lesson 3): one listener per header, calling setSort(column). The arrows (/) update from the current sortKey/sortDir.

Notice what's not here: not a single renderCollection() call after setSort/setPage. It isn't needed — they call notify(), and the main.js subscription (lesson 9) re-renders. The table only describes how the current state looks.

Tip. renderPagination draws a button per page — fine for a few dozen. For thousands of rows you'd show only "1 … 5 6 7 … 40". But the principle is the same: page controls are a derived view of state (currentPage, totalPages), not separately stored state.