Capturing State

Capture the state of the application in the URL. All Gramex apps use this approach. This makes it easy to:

Do not use the URL to capture state if:

Use form-encoding to capture state

When the user performs an action capture the state as form-encoded URL query. For example:

You can use the @gramex/url package to encode/decode state:

<script src="https://cdn.jsdelivr.net/npm/@gramex/url/url.min.js">
  <script>
  <script>
  const query = gramex.url.encode({city: ['Rome', 'Oslo'], top: 10})
  const state = gramex.url.decode(query)
</script>

If you only have single values for keys, use URLSearchParams:

const query = new URLSearchParams({ city: "Rome", top: 10 }).toString();
const state = Object.fromEntries(new URLSearchParams(query));

Store state as a search string

To reload your page on every action, add the state after a ?. For example, /page?city=Rome&top=10.

HTML forms do this automatically. For example, submitting this form will reload the page with ?city=Rome&top=10 added.

<form>
  <label>City: <input name="city" value="Rome" /></label>
  <label>Top: <input name="top" value="10" /></label>
  <button type="submit">Submit</button>
</form>

Use window.location.search to reload the page with the new state:

const query = new URLSearchParams({ city: "Rome", top: 10 }).toString();
window.location.search = query;
// This will immediately reload the page with ?city=Rome&top=10

On page load, you can access the query via window.location.search:

const query = window.location.search;
const state = Object.fromEntries(new URLSearchParams(query));
// Now do what you want with the state, e.g. update the page filters

Store state as a hash

To update your page without reloading, add the state after a #?. For example, /page#?city=Rome&top=10.

Use window.location.hash to update the page without reloading:

window.addEventListener("hashchange", renderPage);

function renderPage() {
  const query = window.location.hash.slice(2);
  const state = Object.fromEntries(new URLSearchParams(query));
  // Now do what you want with the state, e.g. update the page filters
}
render();

const query = new URLSearchParams({ city: "Rome", top: 10 }).toString();
window.location.hash = "?" + query;

When listening to filter changes or button clicks, NEVER update the page directly. Instead, update the hash. The hashchange listener updates the page. (Otherwise, the user state and page go out-of-sync.)