Last active
July 20, 2023 20:05
-
-
Save travishorn/6182fa25d9cc9319149c4b405268295e to your computer and use it in GitHub Desktop.
Submit form on control change without pushing new state to history
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// A pattern I often find myself using consists of a report-type page that | |
// displays any amount of data. At the top of that page is a `<form>` containing | |
// one or more `<select>` elements whose purpose is to filter the data on the | |
// report. | |
// The form uses `method="GET"`, which is great to make sure that the URL stays | |
// in line with what the page shows. A user can bookmark/favorite the URL and | |
// come back to it later. A user can share the URL so other users can see | |
// exactly the same page. | |
// Each `<select>` element has the attribute `onchange="this.form.submit()"` so | |
// the report changes every time a filter is changed. This way the data on the | |
// page stays in line with the filters at all times. | |
// On the server-side, the query parameters are read while generating the page. | |
// However, this approach has a couple downsides: | |
// 1. The history has quickly get out of hand. Each time the user changes a | |
// filter, a new state is pushed to the history. This means that when the | |
// user wants to go back, away from the report, they must click the **back** | |
// button multiple times (once for each time they changed a filter). | |
// 2. When a user changes a filter, looks at the updated report, then clicks the | |
// **back** button, the old version of the report is displayed (as expected), | |
// but the `<select>` they most recently changed still shows their new | |
// selection. So the filter is not in line with what's on the page. | |
// Instead, you can use JavaScript to set behavior on the page so that the | |
// report updates with filter changes as usual, and the **back** button takes | |
// the user back away from the report, ignoring any of the states where a filter | |
// was changed. | |
// To do so... | |
// 1. Remove `onchange="this.form.submit()"` from all `<select>` elements | |
// 2. Give the `<form>` element the attribute `id="filters"` | |
// 3. Include the following JavaScript after all DOM elements have been loaded | |
const filtersForm = document.querySelector("#filters"); | |
const filterControls = filtersForm.querySelectorAll("select"); | |
const handleFilterChange = () => { | |
const formData = new FormData(filtersForm); | |
const searchParams = new URLSearchParams(formData).toString(); | |
history.replaceState(null, '', `?${searchParams}`); | |
window.location.reload(); | |
} | |
filterControls.forEach((fc) => { | |
fc.addEventListener("change", handleFilterChange); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment