Styling & the Gameweek/Season Selector UI
Premier League Predictor: FastAPI & PostgreSQL
Chapter 10 · Styling & the Gameweek/Season Selector UI
Every real route this course has built since Chapter 4 has been exercised against a hardcoded seasonId/gameweekId pair, deliberately left that way to keep each chapter's own example focused. This chapter replaces every one of those constants with a real, working dropdown selector — and gives the whole app the dark-theme styling it's been missing since Chapter 1.
Two Small List Routes This Course Never Quite Needed Until Now
A Shared Selector, Broadcasting One Event
Every page built since Chapter 4 — fixtures, predictions, both league tables — needs to know the currently selected season and gameweek. Rather than having each of those pages reach directly into a selector's own internal variables, the selector broadcasts a single CustomEvent whenever the selection changes, and every page independently listens for it:
selector.js could have exported getSelectedSeasonId()/getSelectedGameweekId() for every other script to call whenever it needs the current selection — but that would mean fixtures.js, predictions.js, and both table scripts would each need to know exactly when to call them (on page load? on some other event?), coupling every page's own logic to selector.js's own timing. Broadcasting one selection-changed event instead means selector.js doesn't need to know or care what else is listening, and every other page only needs to know one event name — the same decoupling this course's own backend has leaned on repeatedly: Chapter 3's SeasonTeam as the one shared table two later chapters both read and write, Chapter 7's compute_league_table() reused directly rather than re-derived. This is that same idea, applied to the frontend.
Resolving Chapter 4's Own Flagged Gap, For Real
Chapter 4 was honest that usedTeamIds only lived in the page's own memory, resetting to empty on every reload and never reflecting fixtures already entered in an earlier visit. Wiring fixtures.js into the new selection-changed event is exactly the natural place to fix that — not by trusting a stale in-memory set, but by re-seeding it from the real server state every time the gameweek actually changes:
Reloading the page — or switching to a different gameweek and back — now reliably shows the real, correct set of already-used teams, fetched fresh from GET /api/gameweeks/{id}/fixtures (Chapter 4's own listing route) every time, rather than an empty set that happened to be correct only by coincidence of a fresh page load.
Real Styling
The same teal accent (#00C7B7/#5EEAD4) and dark surfaces (#0d1117/#161b22) used across every chapter of this course's own documentation — the finished app looks like a genuine continuation of the material teaching it, not a visually disconnected afterthought.
Where This Course Is Headed
Deployment — getting this app running somewhere real, not just localhost (Chapter 11); and a capstone integrating the finished predictor into the existing Astro-based site (Chapter 12).
Hands-On Exercises
Explain why selector.js broadcasts a single CustomEvent rather than exporting getSelectedSeasonId()/getSelectedGameweekId() functions for other scripts to call, and name one other place in this course where a similar decoupling choice was already made.
📄 View solutionExplain exactly how seedUsedTeams resolves the gap Chapter 4 flagged about usedTeamIds resetting on page reload, and what real request it makes to do so.
📄 View solutionBuild the selector into a real page with at least two seasons and two gameweeks to choose from, enter a fixture in one gameweek, switch to the other gameweek and back, and confirm the previously-entered fixture's own two teams are still shown as disabled after switching back — without reloading the page.
📄 View solutionChapter 10 Quick Reference
- GET /api/seasons and GET /api/seasons/{id}/gameweeks — the two small list routes this course never quite needed until the selector required them
- selection-changed — one CustomEvent broadcast whenever season/gameweek changes, decoupling selector.js from every page that reacts to it
- seedUsedTeams() — genuinely resolves Chapter 4's own flagged gap by re-fetching real fixture data on every gameweek switch
- Styling — real, working dark-theme CSS reusing this course's own documentation accent colors, deliberately not a full design system
- Next chapter: Deployment