# Transitioning from element to application

**URL:** <https://discourse.elm-lang.org/t/transitioning-from-element-to-application/9015>\
**Category:** Learn\
**Created:** [March 18, 2023, 4:09pm UTC](https://discourse.elm-lang.org/t/transitioning-from-element-to-application/9015 "2023-03-18T16:09:00Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![AlanQ](https://avatars.discourse-cdn.com/v4/letter/a/e9bcb4/32.png) [@AlanQ](https://discourse.elm-lang.org/u/AlanQ)\
**Post date:** [March 18, 2023, 4:09pm UTC](https://discourse.elm-lang.org/t/transitioning-from-element-to-application/9015/1 "2023-03-18T16:09:00Z")

</div>

I’m trying to make the transition from `Browser.element` to `Browser.application`, but I’m struggling to get started.

* * *

1. In the Guide under [Structuring Web Apps](https://guide.elm-lang.org/webapps/structure.html) it says, “I would have a module for each page, centered around the Model type. Those modules follow The Elm Architecture with the typical `Model`, `init`, `update`, `view`, and whatever helper functions you need.”

A `Model` in each module? Does this not conflict with the idea of keeping all state in one place?

In `Main.elm` we tie the main functions together in a record in a `Browser.*` function. What would tie them together in a (sub-)module?

* * *

1. Under [Navigation](https://guide.elm-lang.org/webapps/navigation.html) it says, " **When someone clicks a link** , like `<a href="/home">Home</a>`, it is intercepted as a [`UrlRequest`](https://package.elm-lang.org/packages/elm/browser/latest/Browser#UrlRequest). So instead of loading new HTML with all the downsides, `onUrlRequest` creates a message for your `update` where you can decide exactly what to do next."

But my `Browser.element` app doesn’t have any links. All of my ‘links’ are of the form `onClick` or `onPress` which generate messages, sometimes leading to an new view. How, and where, should I replace them?

* * *

1. The Document type

```auto
type alias Document msg =
    { title : String
    , body : List (Html msg)
    }

```

Why does `body` have the type `List (Html msg)` and not just simply `Html msg`?

How should we handle this? There is the obvious `[header, main, footer]` structure, but there must be a more fundamental reason why it’s a list.

* * *

1. I have tried looking through Richard Feldman’s [Elm spa Example](https://github.com/rtfeldman/elm-spa-example), but it’s very complex.

Among other things, it makes extensive use of `Html.map`. But the documentation for `Html.map` says, “_This should not come in handy too often. Definitely read [this](https://guide.elm-lang.org/reuse/) before deciding if this is what you want._”  
(ps [this](https://guide.elm-lang.org/reuse/) is a broken link).

And the `let` section of the top level `view` function has my head spinning.

---

<div class="post-metadata">

**Author:** ![Lucas\_Payr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/lucas_payr/32/4993_2.png) [@Lucas\_Payr](https://discourse.elm-lang.org/u/Lucas_Payr)\
**Post date:** [March 18, 2023, 5:13pm UTC](https://discourse.elm-lang.org/t/transitioning-from-element-to-application/9015/2 "2023-03-18T17:13:09Z")

</div>

Technically, you can do all of this by hand, but I would not recommend it.

Instead, I would recommend installing [elm-spa](https://www.elm-spa.dev/).

You start by writing `elm-spa new`, this will generate the main page located at `Pages/Home_.elm`. And yes, a page should have its own Model, init, update and view. But i would let elm-spa create the wiring for you.

To add a new “about” page, just write `elm-spa add /about`. You can even pass values like this: `elm-spa add /user/:id`.

---

<div class="post-metadata">

**Author:** ![Carsten\_Konig](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/carsten_konig/32/4063_2.png) [@Carsten\_Konig](https://discourse.elm-lang.org/u/Carsten_Konig)\
**Post date:** [March 18, 2023, 5:19pm UTC](https://discourse.elm-lang.org/t/transitioning-from-element-to-application/9015/3 "2023-03-18T17:19:06Z")

</div>

1. you use a model for each page (`PageA.Model`, `PageB.Model`, …) and then have a _main_-model in your `Main.elm` with something like this:

```auto
type Model
   = PageA PageA.Model
   | PageB PageB.Model

```

so you have all your state here - depending on which page you are showing one of those.

* * *

1. I would recommend you switch to pages with their own URLs - this is much nicer for the users as they can bookmark or share individual URLs to your pages. So have a URL for each page and decide based on the URL which page you should be showing.

* * *

1. Don’t know but having a `List` is much nicer - at least I always have more than one element inside `body` so this keeps you from having a dummy-`div [] [...]` to wrap this up.

* * *

1. Yes `Html.map`, `Cmd.map` and maybe `Sub.map` is needed to push the `pageModel : PageA.Model`s into `PageA pageModel : Model` to keep then all on the same _main-model_ - this is boilerplate you really circumvent with the type-system Elm gives you when you want to use the obvious and often used _page as components_ with their own `Model, Msg, update, view` TEA-architecture.

---

<div class="post-metadata">

**Author:** ![kanishka](https://avatars.discourse-cdn.com/v4/letter/k/3e96dc/32.png) [@kanishka](https://discourse.elm-lang.org/u/kanishka)\
**Post date:** [March 19, 2023, 4:20am UTC](https://discourse.elm-lang.org/t/transitioning-from-element-to-application/9015/4 "2023-03-19T04:20:00Z")

</div>

> [@AlanQ](#):
>
> Why does `body` have the type `List (Html msg)` and not just simply `Html msg`?

I would expect this to be a list. If body is the html body tag, then I see the value of body as the children of the body tag, which I would expect to be a list.

---

<div class="post-metadata">

**Author:** ![paulh](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/paulh/32/5022_2.png) [@paulh](https://discourse.elm-lang.org/u/paulh)\
**Post date:** [March 21, 2023, 2:03pm UTC](https://discourse.elm-lang.org/t/transitioning-from-element-to-application/9015/5 "2023-03-21T14:03:49Z")

</div>

> [@Carsten\_Konig](#):
>
> 1. you use a model for each page (`PageA.Model`, `PageB.Model`, …) and then have a _main_-model in your `Main.elm` with something like this:
> 
> ```auto
> type Model
> = PageA PageA.Model
> | PageB PageB.Model
> 
> ```
> 
> so you have all your state here - depending on which page you are showing one of those.

Another approach would be to use a flat model:

```auto
type alias Model =
  { pageA : PageA.Model
  , pageB : PageB.Model
  ...
  // Any other fields your App needs
  ...
  }

```

This approach is useful if you want to maintain the state of each page, or if you have additional, non-page-specific ‘settings’ that your app utilizes from time to time.

---

<div class="post-metadata">

**Author:** ![Carsten\_Konig](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/carsten_konig/32/4063_2.png) [@Carsten\_Konig](https://discourse.elm-lang.org/u/Carsten_Konig)\
**Post date:** [March 21, 2023, 2:29pm UTC](https://discourse.elm-lang.org/t/transitioning-from-element-to-application/9015/6 "2023-03-21T14:29:12Z")

</div>

I guess it depends on your need but for my needs (where I want to get to a certain page via a URL and the URL has all the needed initial information to setup that page) this would not work very well and I would not recommend it for an architecture in my teams.

If I need shared state across different pages (I usually do) I add a `session : Session` field to each pages-model and copy this from the current page to the new on page transitions.

That involves a bit of boiler-plate code but it’s a no-brainer and usually I don’t mind - at least not when working with Elm 😉

---

<div class="post-metadata">

**Author:** ![paulh](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/paulh/32/5022_2.png) [@paulh](https://discourse.elm-lang.org/u/paulh)\
**Post date:** [March 21, 2023, 4:58pm UTC](https://discourse.elm-lang.org/t/transitioning-from-element-to-application/9015/7 "2023-03-21T16:58:12Z")

</div>

> [@Carsten\_Konig](#):
>
> (where I want to get to a certain page via a URL and the URL has all the needed initial information to setup that page) this would not work very well

How will that not work very well with a Type Alias? It’s exactly what I do without any issues.

That’s not meant as a criticism, just curious. I’m a self-taught hobbyist that’s been using Elm since 0.18, I’ve got a, very close to, 50k loc Elm project I’ve been working on, and like to keep up with the various ‘how-to’ discussions around best practices etc. One such discussion related to preferring flat models.

I started my current project as you have described, with an Enum Type as the Main model, and passed an additional Session type around. Eventually, I found that there was ‘stuff’ being stored on the Session that I didn’t think should really be there, and it was becoming a bit of a dumping ground. Plus I wanted my pages to maintain their state for the life of the App, for this project that makes sense. So I refactored from an Enum Type to a Type Alias on the Main model, and feel that it is a much better design now.

I don’t mean that to sound like “A Type Alias is better than an Enum Type”, not at all, but for my particular use case, it works for me. Maybe if I refactored again - back to using an Enum Type, the design would improve again… 🤷‍♂️ 😂

I’d be interested to learn what you have against a Type Alias for the Main Model, though - might be something the OP would be interested in too.

---

<div class="post-metadata">

**Author:** ![Carsten\_Konig](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/carsten_konig/32/4063_2.png) [@Carsten\_Konig](https://discourse.elm-lang.org/u/Carsten_Konig)\
**Post date:** [March 21, 2023, 5:04pm UTC](https://discourse.elm-lang.org/t/transitioning-from-element-to-application/9015/8 "2023-03-21T17:04:16Z")

</div>

it’s not about the type alias - it’s about having to construct the full tuple (with all models for each page) for/on every requested page/url - so you need some “invalid” or “empty” page-models for all the other pages.

Overall it’s a representable state (all pages at once) that feels a bit _invalid_ to me - I’d rather have the obvious modeling of the model representing exactly the page shown.

IMHO this is just as flat (meaning no more wrappers) then what the tuple approach would give you.

In the end I don’t think there is a objective right or wrong way to do it (or at least I did not really bother to try and come up with some objective measure of “good” architecture and then went to compare the to approaches against each other) - it’s just what I prefer and the reasoning is more or less what I would give a peer that would ask me my opinion.

---

<div class="post-metadata">

**Author:** ![benjamin-thomas](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/benjamin-thomas/32/3869_2.png) [@benjamin-thomas](https://discourse.elm-lang.org/u/benjamin-thomas)\
**Post date:** [March 22, 2023, 7:22am UTC](https://discourse.elm-lang.org/t/transitioning-from-element-to-application/9015/9 "2023-03-22T07:22:17Z")

</div>

@AlanQ have you seen this resource ?

> **[Beginning Elm](https://elmprogramming.com/restructuring-code.html)**
>
> A gentle introduction to Elm programming language

It explains it all 🙂

---

<div class="post-metadata">

**Author:** ![dwayne](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dwayne/32/5478_2.png) [@dwayne](https://discourse.elm-lang.org/u/dwayne)\
**Post date:** [March 22, 2023, 7:45pm UTC](https://discourse.elm-lang.org/t/transitioning-from-element-to-application/9015/10 "2023-03-22T19:45:10Z")

</div>

> [@AlanQ](#):
>
> 1. In the Guide under [Structuring Web Apps](https://guide.elm-lang.org/webapps/structure.html) it says, “I would have a module for each page, centered around the Model type. Those modules follow The Elm Architecture with the typical `Model`, `init`, `update`, `view`, and whatever helper functions you need.”
> 
> A `Model` in each module? Does this not conflict with the idea of keeping all state in one place?

It doesn’t. Here’s [an example](https://github.com/dwayne/elm-super-rentals/tree/dc499bbcec11c74b067740d3e14c7d2601f2d502/src/Page) of the approach in action, i.e. 1 module per page. [`Main.elm`](https://github.com/dwayne/elm-super-rentals/blob/dc499bbcec11c74b067740d3e14c7d2601f2d502/src/Main.elm) just orchestrates everything.

---

<div class="post-metadata">

**Author:** ![AlanQ](https://avatars.discourse-cdn.com/v4/letter/a/e9bcb4/32.png) [@AlanQ](https://discourse.elm-lang.org/u/AlanQ)\
**Post date:** [March 27, 2023, 2:05pm UTC](https://discourse.elm-lang.org/t/transitioning-from-element-to-application/9015/11 "2023-03-27T14:05:45Z")

</div>

Many thanks for all the interesting replies and explanations, gratefully received.  
It looks like elm-spa is the way to go… 🙂  
[Edit] …I’ve just discovered [Elm Land](https://elm.land/): Ryan’s upgrade of elm-spa…

* * *

> [@paulh](#):
>
> might be something the OP would be interested in too.

I’m very interested in this whole branch of the topic 🙂  
`Model = Custom Type` vs `Model = Record`.

In a previous question I asked, [Is it inefficient to pass the whole model from function to function?](https://discourse.elm-lang.org/t/is-it-inefficient-to-pass-the-whole-model-from-function-to-function/8379)

I think a relevant point from this discussion is that a complex structure like the model is _passed by reference_. So, whether the model is data for each page plus session data inside a record, or a custom type of one page at a time plus session data, there’s no efficiency gain or loss.

> [@paulh](#):
>
> This [model as record] approach is useful if you want to maintain the state of each page…

Which I think I am typically very likely to need.

* * *

> [@Carsten\_Konig](#):
>
> it’s not about the type alias - it’s about having to construct the full tuple [record] (with all models for each page) for/on every requested page/url - so you need some “invalid” or “empty” page-models for all the other pages.

Could we somehow use each page’s `init` to populate the ‘empty’ values?  
Alternatively, might the record entry for each page be a `Maybe`?

I’m still finding my way around _elm-spa_, but it seems to solve this one by combining Carsten’s and Paul’s approaches — a `custom type` _inside_ a `record` — plus auto-generation:  
The underlying model is a record in _.elm-spa/defaults/Main.elm_

```auto
module Main exposing (main) 
import Gen.Pages as Pages 
type alias Model =
    { url : Url
    , key : Key
    , shared : Shared.Model
    , page : Pages.Model
    }

```

`Pages.Model` = `Model.Model`:

```auto
type Model
    = Redirecting_
    | Home_ Gen.Params.Home_.Params ()
    | NotFound Gen.Params.NotFound.Params

```

So each time a page is added (`elm-spa add`), a new option is added to the `Model.Model`.

* * *

_Minor note on the Document body type_

> [@Carsten\_Konig](#):
>
> 1. Don’t know but having a `List` is much nicer - at least I always have more than one element inside `body` so this keeps you from having a dummy-`div [] [...]` to wrap this up.

> [@kanishka](#):
>
> I would expect this to be a list. If body is the html body tag, then I see the value of body as the children of the body tag, which I would expect to be a list.

Even when writing raw html, I always use a ‘dummy’ `div` because it feels wrong to style the top-level `body`. And, in the case of the `Document` type, there is no mechanism to style the `body`:

- if it has three unstyled child `div`s, they sit one above the other
- style them as `float: left` and they sit side by side
- but if we want flexbox styling, we can’t style `body` as a `flex` parent. So, for example, everyone using `elm-ui` ends up with something like `body = [myElmUiBody]`.

It’s like a painting studio that favours the painters of triptychs over those who just use a single canvas: every frame comes with a hinge, whether you need it or not 😉

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [April 6, 2023, 2:06pm UTC](https://discourse.elm-lang.org/t/transitioning-from-element-to-application/9015/12 "2023-04-06T14:06:31Z")

</div>

Closed on April 6, 2023, 2:06pm UTC

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
