modelelmalgebraic-data-types

Access values from top level model


I am creating my first elm application. It is a website with multiple pages, and a side bar/ top bar to navigate to the available pages. I have a top level model that looks like this:

top level model .

I am creating a top bar which displays the user's username. The username is in the Components Model: components model. I purposely only define the userName in this model because I only want to call it once and only use it in the 'top nav bar'.

In the top-level view function, I have a function which creates the top and side bar, and then displays the respective page. view function.

My problem is, that I want to extract the username from the Components Model and feed it through the 'TopBar.viewTopbar' function as a string. I am struggling to get this value from the Components Model since the Model field in the top-level view function is a union type containing a list of models. Does anyone know the best way to get the 'username' value so it can be displayed on the top bar which will be seen on every page?


Solution

  • I'm not sure if you will be happy with my answer, but if you want to render a string in every top-level view, that value must also exist in every top-level model.

    So you will either need to have something like this

    username : Model -> String
    username global =
        case global of
            Redirect model ->
                model.username
            NotFound session ->
                session.user.name
            Login model ->
                "invalid state"
            ...
    

    or change your top-level data structure.

    I would propose to change your top-level data structure, as I assume that you will also want to pass additional data to your Sidebar.viewSidebar and Topbar.viewTopbar functions in the future to e.g. highlight the currently visited page in a menu.

    My first draft could look something like this:

    type alias Model =
        { session: Session
        , currentPage: Page
        }
    
    type Session
        = Anonymous
        | User { name: String, avatar: Maybe String }
    
    type Page = Login | Loggedout | Root | PageA
    

    For further learning, I would recommend watching two talks:

    In "Make data structures" by Richard Feldman he talks about structuring code and how trying to create independent components can lead to complex and error-prone code (link shows an example of impossible state).
    And in "Life of a file" by Elm creator Evan Czalicki, he talks about how for him coding works best when he does not try to create components or introduce abstractions from the beginning, but instead try to work in a single file as long as possible before splitting out code. And then only extract data structures and code dealing with them as needed (and not to e.g. look similar in the file system).

    In Elm, having many small modules is more often an anti-pattern than having few very long ones. >1000 lines is not considered bad practice.

    You might also want to have a look at this discourse thread where multiple people share how they scaffold their folder structure.