So I have been sidetracked a bit learning how to handle REST calls in Elm
and figuring out what help functions I can write around that to try and
wrap up a service + boilerplate in a way that provides the simplest
interface to a consumer of it.
I have a screen that displays user accounts and lets an admin take actions
around those accounts. Prior to displaying that screen a list of accounts
(paginated) needs to be fetched from the server. So I thought a bit about
how to initialize each screen.
I could initialize in a global router for the whole application - or
perhaps more neatly delegate the initialization to each module that needs
it. I decided to go for the second option. I needed somewhere to trigger
the initialization action, and also inevitably this routing logic gets
mixed up with handling the current authenticated or not authenticated state.
If not authenticated - the current location is changed to '#welcome', which
is the login page. I also save the location that was trying to be accessed,
so it can be put back after a login. Before introducing the concept of an
initializer for each location, I did not have to do that, as the location
in the url simply stayed put on the welcome screen. But now that I want an
initializer for each route, I need to explicitly change the location to
'#welcome' to login, then back to the protected route after, in order to
trigger its initializer.
The initializers are set up as events on each module, and I used
Cmd.Extra.message to turn them into Elm commands and invoke the update
function for the module. Code is below.
What I like about this vs what I have experienced previously with Angular -
my router is just a function. It is not config that I pass to some other
angular router implementation. I built my own function and make it work in
the way that I want routing to work without that being dictated or limited
by what a framework offers me. I haved used elm-route-url, but that just
seems to offer a convenient way of directing route changes as Msgs which
are directed to the update function, which feels like the right way to do
it. The function you see below called 'selectLocation' is just a
convenience function that I split out of the update function to stop it
getting too big.
All in all, I feel that Elm was not overly difficult to work with - the
types of the functions in elm-route-url pretty much guide you to how it is
used - and very flexible in allowing me to implement whatever routing
functionality I need. Very nice.
'filterNothing' removes the Maybe.Nothings from a list - I probably could
have avoided using Maybes at all and built the list of Cmds more directly.
I think I will refactor to achieve that.
{-
This is the main router for the application, invoked on all url location
changes.
When not logged in and not already on the welcome page, this will
forward to the welcome
page to log in. The location being requested will be saved in the auth
forward location, so
that it can be forwarded to upon succesfull login.
When forwarding to a location with an 'Init' event available, this will
be triggered
in order that a particular location can initialize itself.
-}
selectLocation : Model -> String -> ( Model, Cmd Msg )
selectLocation model location =
let
-- Flag indicating whether the welcome location should be navigated
to.
jumpToWelcome =
not model.auth.authState.loggedIn && location /= "welcome"
-- Maybe a command to jump to the welcome location.
jumpToWelcomeCmd =
if jumpToWelcome then
Navigation.newUrl "#welcome" |> Just
else
Nothing
-- Saves the location as the current forward location on the auth
state.
forwardLocation authState =
{ authState | forwardLocation = "#" ++ location }
-- When not on the welcome location, the current location is saved
as the
-- current auth forwarding location, so that it can be restored
after a
-- login.
jumpToWelcomeModel =
if location /= "welcome" then
{ model | auth = forwardLocation model.auth }
else
model
-- Choses which tab is currently active.
tabNo =
Dict.get location Main.View.urlTabs
|> Maybe.withDefault -1
-- Maybe a command to trigger the 'Init' event when navigating to a
location
-- with such an event.
initCmd =
if not jumpToWelcome then
case location of
"accounts" ->
Cmd.Extra.message (AccountsMsg Accounts.Types.Init)
|> Just
x ->
Nothing
else
Nothing
-- The model updated with the currently selected tab.
selectTabModel =
{ jumpToWelcomeModel | selectedTab = tabNo }
in
( selectTabModel, Cmd.batch (filterNothing [ jumpToWelcomeCmd,
initCmd ]) )
--
You received this message because you are subscribed to the Google Groups "Elm
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.