Handle page models in Router.infer
See original GitHub issueThe problem: we have an application with several pages that are routed via Router.infer
. We would like to keep a piece of model that is specific to the current page. For example, say /counter
has a model of type Counter.Model
, /data/{dataId}
has a model of type Data.Model
, and /
and /hello/{name}
have no specific model. We don’t want to keep all these models side by side in the global app model and have to juggle their behavior when switching pages; instead, we want to only have the model relevant to the current page.
Currently, the only solution to this problem is what @kunjee17 shows in #78: defining a separate union for the model, with a case for each page that needs one. This means a bunch of boilerplate with partial matching at every use site, which is far from ideal.
Instead, we should be able to include the page route and model together in the same union. For example with something like this:
type Page =
// A page can have no model...
| [<EndPoint "/">]
Home
// ... or just a page model...
| [<EndPoint "/counter"; PageModel "counter">]
Counter of counter: Counter.Model
// ... or just path arguments...
| [<EndPoint "/hello/{name}">]
Hello of name: string
// ... or both.
| [<EndPoint "/data/{dataId}"; PageModel "data">]
Data of dataId: int * data: Data.Model
The inconvenient would be that when using router.Link
, you need to pass something as the model (presumably Unchecked.defaultof<_>
, which we might alias for convenience).
A question that needs to be resolved is how to handle the case when the page is set from the URL. This happens on page startup, and when the user clicks a link. We generate a Page value from the URL, but that means that we need to have a “default” model value to fill that field in. A possibility would be to provide it as an extra argument to Router.infer
like this:
let defaultPageModel = function
| Counter _ -> box Counter.defaultModel
| Data _ -> box Data.defaultModel
| Home | Hello _ -> null
let router = Router.inferWithModel SetPage (fun model -> model.page) defaultPageModel
Bolero would call this function once per case with a dummy Page just to get the corresponding default model. Unfortunately this function has to return obj
, since each case can have a different type of model (or none at all). I would love suggestions on how to make this better typed! (without switching to a dependently-typed language 😄)
If the app needs more specific handling (for example, if the user is on /data/1
and clicks a link to /data/2
, should we keep the existing page model or reset it to the value from defaultPageModel
?), it can be done in the update function’s handling of SetPage
.
Issue Analytics
- State:
- Created 4 years ago
- Reactions:2
- Comments:9 (4 by maintainers)
Top GitHub Comments
I have the same problem/question in my applications that use Elmish.WPF. It would be nice if a solution could be found using Elmish, at least kind of partially, but I understand that could be a tall order.
That seems to be exactly what I was looking for. Thanks for the help!