# How to structure an Elm project?

The answer to this question can be found in the [Beginning Elm book](https://elmprogramming.com/restructuring-code.html).\
This question will therefore be removed at some time in the future.

{% hint style="info" %}
**Do not overuse:** Files are allowed to get quite big without needing to split them.
{% endhint %}

{% tabs %}
{% tab title="Problem" %}
{% code title="Todo.elm" %}

```
type Task =
    Task
        { name : String
        , completed : Bool
        }

createTask : String -> Task

completeTask : Task -> Task

type Form a =
    Valid a
    | Invalid a
    | Partial a

validate : (Form a -> Form ()) -> Form a -> Form a

type alias TaskForm =
    { name : String
    , validated : Bool
    }

validateTaskForm : Form TaskForm -> Form ()

type User =
    User
        { name : String
        , lastOnline : Posix
        }

createUser : String -> Posix -> User

type alias UserForm =
    { name : String
    , password : String
    , validated : Bool
    }

validateUserForm : Form UserForm -> Form ()

type alias TodoPageModel =
    { form :
        Form TaskForm
    , todo : Array Task
    , User : User
    }

type alias LoginPageModel =
    Form UserForm

type Model =
    LoginPage LoginPageModel
    | TodoPage TodoPageModel

type LoginPageMsg =
    NameEntered String
    | PasswordEntered String
    | Submited 
    | GotTime Posix

type TodoPageMsg =
    LoggedOut
    | TaskAdded String
    | TaskCompleted Int
    | TaskDeleted

type Msg =
    LoginSpecific LoginPageMsg
    | TodoSpecific TodoPageMsg

init : () -> Model

updateTodoPage : TodoPageModel -> (TodoPageModel, Cmd TodoPageMsg)

updateLoginPage : LoginPageModel -> (LoginPageModel, Cmd LoginPageMsg)

update : Msg -> (Model, Cmd Msg) -> (Model, Cmd Msg)

viewUserForm : Form UserForm -> Html Msg

viewLoginPage : LoginPageModel -> Html Msg

viewTask : Task -> Html Msg

viewTaskForm : Form TaskForm -> Html Msg

viewTodoPage : TodoPageModel -> Html Msg

view : Model -> Html Msg

subscription : Model -> Sub Msgexpos
```

{% endcode %}
{% endtab %}

{% tab title="Solution" %}
{% code title="Main.elm" %}

```
importing Todo.Page.Login as LoginPage
importing Todo.Page.Todo as TodoPage

type Model =
    LoginPage LoginPage.Model
    | TodoPage TodoPage.Model

type Msg =
    LoginSpecific LoginPage.Msg
    | TodoSpecific TodoPage.Msg

init : () -> Model

update : Msg -> (Model, Cmd Msg) -> (Model, Cmd Msg)

view : Model -> Html Msg

subscription : Model -> Sub Msg
```

{% endcode %}

{% code title="Page/Login.elm" %}

```
module Todo.Page.Login exposing (Model,Msg,view,update)

importing Todo.Data.Form as Form exposing (Form)
importing Todo.Data.User as User exposing (User,UserForm)

type alias Model =
    Form UserForm
    
type Msg =
    NameEntered String
    | PasswordEntered String
    | Submited 
    | GotTime Posix

update : Model -> (Model, Cmd Msg)

viewUserForm : Form UserForm -> Html Msg

view : Model -> Html Msg
```

{% endcode %}

{% code title="Page/Todo.elm" %}

```
module Todo.Page.Login exposing (Model,Msg,view,update)

importing Todo.Data.Task as Task exposing (Task,TaskForm)
importing Todo.Data.User as User exposing (User,UserForm)

type alias Model =
    { form :
        Form TaskForm
    , todo : Array Task
    , User : User
    }

type Msg =
    LoggedOut
    | TaskAdded String
    | TaskCompleted Int
    | TaskDeleted

update : Model -> (Model, Cmd Msg)

viewTask : Task -> Html Msg

viewTaskForm : Form TaskForm -> Html Msg

view : Model -> Html Msg
```

{% endcode %}

{% code title="Data/Task.elm" %}

```
module Todo.Data.Task exposing (Task,create,complete,validate)

importing Todo.Data.Form as Form exposing (Form)

type Task =

    Task
        { name : String
        , completed : Bool
        }

create : String -> Task

complete : Task -> Task

type alias TaskForm =
    { name : String
    , validated : Bool
    }

validate : Form TaskForm -> Form ()
```

{% endcode %}

{% code title="Data/Form.elm" %}

```
module Todo.Data.Form exposing (Form(..),validate)

type Form a =
    Valid a
    | Invalid a
    | Partial a

validate : (Form a -> Form ()) -> Form a -> Form a
```

{% endcode %}

{% code title="Data/User.elm" %}

```
module Todo.Data.User exposing (User,UserForm,create,validate)

importing Todo.Data.Form as Form exposing (Form)

type User =
    User
        { name : String
        , lastOnline : Posix
        }

create : String -> Posix -> User

type alias UserForm =
    { name : String
    , password : String
    , validated : Bool
    }

validate : Form UserForm -> Form ()

```

{% endcode %}
{% endtab %}
{% endtabs %}

## Question

How should I structure my Elm project?

## Answer

Use the following file structure:

* Main.elm - Contains the main code
* Data.elm - Contains utility functions for types (like constants)
  * Data/.. - Contains types. Group them logically, for example `User` and `UserForm` into `Data/User.elm`.
* View\.elm - Contains utility functions for views (like view specific constants and very general function.)
  * View/.. - Contains different Views. Sometimes a type has different views. A login page might have a special view for a wrong login.
* Page.elm - Contains utility functions for pages. For page-transitions its handy to store the different models in here.
  * Page/.. - Contains a Model/View/Update for every page.
* .. - in the same style you can add your project specific folders like a separate folder for validation.

## Further reading

* 📄**Article:** [NoRedInk Style Guide](https://github.com/NoRedInk/elm-style-guide/blob/master/README.md)
* 👥**Thread:** [Code structure/architecture](https://discourse.elm-lang.org/t/code-structure-architecture/4030)
* 📄**Article:** Tour of an [Open-Source Elm SPA](https://dev.to/rtfeldman/tour-of-an-open-source-elm-spa) by Richard Feldman
* 🎥**Video:** [The life of a file](https://www.youtube.com/watch?v=XpDsk374LDE) by Evan Czaplicki
