Architecture of elm-lang

ToDo List with elm-lang architecture

Architecture

Elm architecture
<body>
<div id="elm-app"></div>
<script>
node = document.getElementById("elm-app")
// Embed the application in selected node
elmApp = Elm.ToDoApp.embed(node)
</script>
</body>
module ToDoApp exposing (main)import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Json.Decode as Json

Model

type alias Model =
{ list : List String
, inputValue : String
}
  • a list of all the items added
  • string value typed in the input

Messages

type Msg
= AddItem String
| RemoveItem Int
| InputChange String
  • AddItem — will be triggered when add button is clicked and should add a new item to the list. It accepts string (which will be the string entered in input) as “parameter/argument”.
  • RemoveItem — will be triggered when user clicks on the cross icon of an existing item, to remove it. It accepts integer, the index of the item to be deleted.
  • InputChange — will be triggered to indicate value in the input has changed. It accepts string argument which is new string.

update

  • updated state
  • another command (in case you do not want to trigger you can return Cmd.none like we are doing in below)
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
AddItem description ->
case description of
"" ->
( model, Cmd.none )
val ->
{ model
| list = model.list ++ [ val ]
, inputValue = ""
}
! []
RemoveItem index ->
( { model
| list =
(List.take index model.list)
++ (List.drop (index + 1) model.list)
}
, Cmd.none
)
InputChange inputStr ->
( { model
| inputValue = inputStr
}
, Cmd.none
)

view

view : Model -> Html Msg
view model =
section [ class "todoapp" ]
[ div [ class "input-container" ]
[ input [ class "new-todo", onInput InputChange, value model.inputValue ]
[]
, button
[ class "add-button", onClick <| AddItem model.inputValue ]
[ text "Add Item" ]
]
, ul [ class "todo-list" ]
(List.indexedMap addListItem model.list)
]
addListItem : Int -> String -> Html Msg
addListItem index description =
li []
[ label [] [ text description ]
, button [ class "destroy", onClick (RemoveItem index) ] []
]

Init

init : ( Model, Cmd Msg )
init =
( { list = [], inputValue = "" }, Cmd.none )

Subscribe

subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none

Program

main : Program Never Model Msg
main =
Html.program
{ update = update
, view = view
, init = init
, subscriptions = subscriptions
}

File Structure

File Structure
-- Main.js
module HelloWorld exposing (main)
import Html
import ToDoApp.State as State
import ToDoApp.Types as Types
import ToDoApp.Views.Layout as Layout
main : Program Never Types.Model Types.Msg
main =
Html.program
{ update = State.update
, view = Layout.view
, init = State.init
, subscriptions = State.subscriptions
}
-- ToDoApp/Types.elm
module ToDoApp.Types exposing (..)
type alias Model =
{ list : List String
, inputValue : String
}
type Msg
= AddItem String
| RemoveItem Int
| InputChange String
-- ToDoApp/State.elm
module ToDoApp.State exposing (..)
import ToDoApp.Types as Typesinit : ( Types.Model, Cmd Types.Msg )
init =
( { list = [], inputValue = "" }, Cmd.none )
subscriptions : Types.Model -> Sub Types.Msg
subscriptions model =
Sub.none
update : Types.Msg -> Types.Model -> ( Types.Model, Cmd Types.Msg )
update msg model =
case msg of
Types.AddItem description ->
case description of
"" ->
( model, Cmd.none )
val ->
{ model | list = model.list ++ [ val ], inputValue = "" } ! []
Types.RemoveItem index ->
{ model | list = (List.take index model.list) ++ (List.drop (index + 1) model.list) } ! []
Types.InputChange inputStr ->
{ model | inputValue = inputStr } ! []
-- ToDoApp/Views/Input.elm
module ToDoApp.Views.Input exposing (view)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import ToDoApp.Types as Types
view : Types.Model -> Html Types.Msg
view model =
div [ class "input-container" ]
[ input [ class "new-todo", onInput Types.InputChange, value model.inputValue ]
[]
, button
[ class "add-button", onClick <| Types.AddItem model.inputValue ]
[ text "Add Item" ]
]
-- ToDoApp/Views/Layout.elm
module ToDoApp.Views.Layout exposing (view)
import Html exposing (..)
import Html.Attributes exposing (..)
import ToDoApp.Views.Input as Input
import ToDoApp.Views.ToDoItem as ToDoItem
import ToDoApp.Types as Types
view : Types.Model -> Html Types.Msg
view model =
section [ class "todoapp" ]
[ Input.view model
, ul [ class "todo-list" ]
(List.indexedMap ToDoItem.addListItem model.list)
]
-- ToDoApp/Views/ToDoItem.elm
module ToDoApp.Views.ToDoItem exposing (addListItem)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import ToDoApp.Types as Types
addListItem : Int -> String -> Html Types.Msg
addListItem index description =
li []
[ label [] [ text description ]
, button [ class "destroy", onClick (Types.RemoveItem index) ] []
]

Resources

Github

Live Demo

--

--

--

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

A Week in the Life of a Software Engineer at Perlego

Developer Chris working on his computer

How to Prepare for your First Week at a Coding Bootcamp

How To Register A Domain Name?

Monthly Update — May 2020

Azure API Management : Introduction — English Version

My Zuri Expectations.

CONCEPT OF DATABASE MANAGEMENT SYSTEM (DBMS).

Building a $300k / year no-code product portfolio

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Digvijay Upadhyay

Digvijay Upadhyay

More from Medium

Writing better Elm code with simple List transformations

Moving into the subscription model

AppsFlyer’s Open Source Libraries for Clojure and Protocol-Buffers

Run Puppeteer in Akka.js