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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to