Open mpdairy opened 7 years ago
Well I haven't implemented any routing apps yet. At the most basic level I can think of the following scheme. However it would be good to brainstorm on an ideal API.
So let's say we have data Route = A | B | C
. And we want to show widgetA
, widgetB
, widgetC
respectively. Then it could look like this -
getRoute = <IO CODE TO FETCH AND PARSE CURRENT URL>
main = do
route <- getRoute
case route of
A -> widgetA
B -> widgetB
C -> widgetC
That would handle the routing only once in the beginning. So to handle routing changes in real time we can put in a short circuit operation at the top level -
getRoute = <IO CODE TO FETCH AND PARSE CURRENT URL>
awaitRouteChange = <IO CODE TO AWAIT A PAGE CHANGE>
displayCurrentRoute = do
route <- getRoute
case route of
A -> widgetA
B -> widgetB
C -> widgetC
main = forever $ displayCurrentRoute <|> awaitRouteChange
This will abort the current widget when the route changes, and redraw the widget for the new route.
I ended up using the ghcjs-servant-router library (https://github.com/plow-technologies/servant-ghcjs-router), but I modified it so all the routes return a concur Widget and the initRouter
function runs runWidgetInBody . forever
on the widget returned by the route. With that I can do nested routes and wrap widgets around nested routes to provide menus or back buttons. If anybody wants me to make a nice fork of it with a demo, let me know.
@mpdairy that is awesome! An example demo would be great!
Have you thought about a clever way to do routing with Concur? I'm planning on using something like
servant-router
to parse a Servant API in the client and then load the correct corresponding widget, and something likeghcjs-servant-client
to generate functions to jump to the route (maybe just by doing a JS History pushState).Then I think I'd just need a loop at the bottom that listened for changes to the location/history state and loaded the new widget / killing the old one.
But the big downside of this is that whenever I want to route a change I can't use the nice monad flow to do menus like in your example, plus it seems pretty bad to be able to jump to any other route within any widget; it could turn to spaghetti real fast.