solid-router icon indicating copy to clipboard operation
solid-router copied to clipboard

Support for blocking navigation (via integration)

Open Brendan-csel opened this issue 2 years ago • 3 comments

Adds minimal core support for blocking navigation. Use case is providing some control over navigating away from a route that has unsaved changes.

Leaving a route can occur in many ways - and blocking them all is challenging:

  1. User clicks a normal anchor
  2. User clicks a router <A> component
  3. Code calls navigate
  4. Code calls browser history APIs directly
  5. User refreshes the page
  6. User types in URL
  7. more?...

Some of these can be handled somewhat in user land, eg by listening to window.beforeunload for (5 & 6), but others need some assistance from router.

In Solid's case, blocking seems relevant in two places: a) The router internals (ie the navigateFromRoute function) handles 2 & 3 b) The router integration (ie suppress notifying the location has changed) handles 1.

This PR is specific to (a) and enables (b). It enables the router integration to optionally provide a block function that will bail out of navigateFromRoute.

It is expected that block function will originate from the app, probably as an option to the integration. It is also likely the block function will itself be used to support some higher-level component such as a useBlocker hook - but these may be best experimented with in userland via custom integrations. It is noteworthy the parameters to the block function are the same as those used when calling navigate. This is intentional as the app may wish to save those parameters and block immediate navigation - and then kick navigation off again in the near future - for example if the user confirms they are okay to leave the page without saving.

Note This PR does not update the built-in integrations to utilize the block function. I have tested with a custom integration here that implements (b) - but I think that is a separate concern.

Brendan-csel avatar Oct 15 '22 03:10 Brendan-csel

To clarify why the block function needs to be available to the router integration (in addition to the internals)...

...in the event of a navigation being blocked, the integration (path, hash, etc) needs to revert the browser url state appropriately eg window.history.go(-1), while also preventing notifying the router of both the original url change and the one caused by the "revert". That process may differ by integration?

Brendan-csel avatar Oct 15 '22 19:10 Brendan-csel

If your curious, this commit (~~https://github.com/cselnz/solid-router/commit/772615038535562b619f7d63479f9df5f95fefe7~~) suggest how this new block ability might be used in the integrations. Note - I'm testing that in our apps using hash integration - so the path integration will need further testing.

~~EDIT: this one does the proper depth thing when reverting the url ( https://github.com/cselnz/solid-router/commit/920d6fb96ad9a76e1d9217e9c1c26251f16562ff)~~

Okay now, after several commits and a day of tuning, we've got a branch that implements the integrations using the hook PR ...soon to be in production in our apps. https://github.com/cselnz/solid-router/tree/publish

Brendan-csel avatar Oct 15 '22 22:10 Brendan-csel

Scrapping this in favour the much more comprehensive PR https://github.com/solidjs/solid-router/pull/186

Brendan-csel avatar Oct 20 '22 22:10 Brendan-csel