Skip to content

Commit ff855c5

Browse files
authored
Merge pull request #34 from MI-AFP/elm-tutorials-updated
Elm guidelines updated
2 parents 0a97827 + 6e99813 commit ff855c5

4 files changed

Lines changed: 227 additions & 170 deletions

File tree

tutorials/09_elm-intro.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ Now you may be wondering, what will be in this file? How do I add Elm files to
221221
my project? How do I see it in the browser? How will my code grow? Do I need
222222
more directories? What about tests? Etc.
223223
224-
Check out <https://elm-lang.org/0.19.0/init> for all the answers!
224+
Check out <https://elm-lang.org/0.19.1/init> for all the answers!
225225
226226
Knowing all that, would you like me to create an elm.json file now? [Y/n]: y
227227
Okay, I created it. Now read that link!

tutorials/10_elm-tea.md

Lines changed: 114 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -10,55 +10,6 @@ Elm program is set up using [Browser](https://package.elm-lang.org/packages/elm/
1010
- `application` - Creates single page application, Elm controls not only the whole document but also Url changes.
1111

1212

13-
## Forms
14-
15-
Form elements are created the same way as other HTML elements using functions from [Html](https://package.elm-lang.org/packages/elm/html/latest/Html) module and attributes from [Html.Attributes](https://package.elm-lang.org/packages/elm/html/latest/Html-Attributes) module from [elm/html](https://package.elm-lang.org/packages/elm/html/latest/) package.
16-
17-
We can use `onInput` from [Html.Events](https://package.elm-lang.org/packages/elm/html/latest/Html-Events) module to detect input events and create a message for our update function.
18-
19-
The loop is the following:
20-
- user changes the value in an input field
21-
- a new message is created
22-
- the update function is called with the message and it updates the model with the new value
23-
- input field is re-rendered with the new value
24-
25-
26-
Here is a simple example with a single input field:
27-
28-
```elm
29-
import Browser
30-
import Html exposing (Html, input)
31-
import Html.Attributes exposing (placeholder, value)
32-
import Html.Events exposing (onInput)
33-
34-
main = Browser.sandbox { init = init, update = update, view = view }
35-
36-
type Msg = NameChanged String
37-
38-
type alias Model = { name : String }
39-
40-
init : Model
41-
init =
42-
{ name = "" }
43-
44-
update : Msg -> Model -> Model
45-
update msg model =
46-
case msg of
47-
NameChanged newName ->
48-
{ model | name = newName }
49-
50-
view : Model -> Html Msg
51-
view model =
52-
input
53-
[ placeholder "Your name"
54-
, value model.name
55-
, onInput NameChanged ]
56-
[]
57-
```
58-
59-
When we need more complex forms in our application, there are packags to handle forms like [etaque/elm-form](https://package.elm-lang.org/packages/etaque/elm-form/latest/).
60-
61-
6213
## JSON
6314

6415
It is very common to use JSON format when communicating with different APIs. In JavaScript, JSON is usually turned into a JavaScript object and used within the application. However, this is not the case in Elm since we have a strong type system. Before we can use JSON data, we need to convert it into a type defined in Elm. There is the [elm/json](https://package.elm-lang.org/packages/elm/json/latest/) package for that.
@@ -81,87 +32,89 @@ For example, we have this JSON representing a TODO:
8132
To get the `label` field, we can define a decoder like this:
8233

8334
```elm
84-
import Json.Decode as D exposing (Decoder)
35+
import Json.Decode as Decode
8536

86-
labelDecoder : Decoder String
37+
labelDecoder : Decode.Decoder String
8738
labelDecoder =
88-
D.field "label" D.string
39+
Decode.field "label" Decode.string
8940
```
9041

9142
There are functions to decode other primitives, like `bool` or `int`. However, we usually need more than just one field. We can combine decoders using `map` functions from `Json.Decode` module, e.g. `map3`.
9243

9344
```elm
45+
import Json.Decode as Decode
46+
9447
map3 :
9548
(a -> b -> c -> value)
96-
-> Decoder a
97-
-> Decoder b
98-
-> Decoder c
99-
-> Decoder value
49+
-> Decode.Decoder a
50+
-> Decode.Decoder b
51+
-> Decode.Decoder c
52+
-> Decode.Decoder value
10053
```
10154

10255
We can then define our own type for TODO and a decoder.
10356

10457
```elm
105-
import Json.Decode as D exposing (Decoder)
58+
import Json.Decode as Decode
10659

10760
type alias Todo =
10861
{ id : Int
10962
, label : String
11063
, completed : Bool
11164
}
11265

113-
todoDecoder : Decoder Todo
66+
todoDecoder : Decode.Decoder Todo
11467
todoDecoder =
115-
D.map3 Todo
116-
(D.field "id" D.int)
117-
(D.field "name" D.string)
118-
(D.field "completed" D.bool)
68+
Decode.map3 Todo
69+
(Decode.field "id" Decode.int)
70+
(Decode.field "name" Decode.string)
71+
(Decode.field "completed" Decode.bool)
11972
```
12073

121-
There is a package [NoRedInk/elm-json-decode-pipeline](https://package.elm-lang.org/packages/NoRedInk/elm-json-decode-pipeline/latest) for more convenient JSON decoder. It is especially useful for large and more complex objects. We could rewrite the previous example using pipeline:
74+
There is a package [NoRedInk/elm-json-decode-pipeline](https://package.elm-lang.org/packages/NoRedInk/elm-json-decode-pipeline/latest) for more convenient JSON decoders. It is especially useful for large and more complex objects. We could rewrite the previous example using pipeline:
12275

12376
```elm
124-
import Json.Decode as D exposing (Decoder)
125-
import Json.Decode.Pipeline exposing (required)
77+
import Json.Decode as Decode exposing (Decoder)
78+
import Json.Decode.Pipeline as Pipeline
12679

12780
type alias Todo =
12881
{ id : Int
12982
, label : String
13083
, completed : Bool
13184
}
13285

133-
todoDecoder : Decoder Todo
86+
todoDecoder : Decode.Decoder Todo
13487
todoDecoder =
135-
D.succeed Todo
136-
|> required "id" D.int
137-
|> required "name" D.string
138-
|> required "completed" D.bool
88+
Decode.succeed Todo
89+
|> Pipeline.required "id" Decode.int
90+
|> Pipeline.required "name" Decode.string
91+
|> Pipeline.required "completed" Decode.bool
13992
```
14093

14194
It is not that big change in this case, however, we only have `map8` function in `Json.Decode` so this library comes handy if we need more. Moreover, it has other functions to define for example [optional](https://package.elm-lang.org/packages/NoRedInk/elm-json-decode-pipeline/latest/Json-Decode-Pipeline#optional) or [hardcoded](https://package.elm-lang.org/packages/NoRedInk/elm-json-decode-pipeline/latest/Json-Decode-Pipeline#hardcoded) values.
14295

14396

14497
### Encoders
14598

146-
When we want to send something to an API we need to do the opposite -- turn the Elm value into JSON value. We use functions form [Json.Encode](https://package.elm-lang.org/packages/elm/json/latest/Json-Encode) package for that. There is a type called `Value` which represents a JavaScript value and functions to convert Elm primitives, lists and objects into `Value` type.
99+
When we want to send something to an API we need to do the opposite -- turn the Elm value into JSON value. We use functions from [Json.Encode](https://package.elm-lang.org/packages/elm/json/latest/Json-Encode) package for that. There is a type called `Value` which represents a JavaScript value and functions to convert Elm primitives, lists and objects into `Value` type.
147100

148101
Here's an example using the TODO from decoders example.
149102

150103
```elm
151-
import Json.Encode as E
104+
import Json.Encode as Encode
152105

153106
type alias Todo =
154107
{ id : Int
155108
, label : String
156109
, completed : Bool
157110
}
158111

159-
encodeTodo : Todo -> E.Value
112+
encodeTodo : Todo -> Encode.Value
160113
encodeTodo todo =
161-
E.object
162-
[ ( "id", E.int todo.id )
163-
, ( "label", E.string todo.label )
164-
, ( "completed", E.bool todo.completed )
114+
Encode.object
115+
[ ( "id", Encode.int todo.id )
116+
, ( "label", Encode.string todo.label )
117+
, ( "completed", Encode.bool todo.completed )
165118
]
166119
```
167120

@@ -177,7 +130,8 @@ Here is an example for getting TODO using the decoder defined in previous sectio
177130
```elm
178131
import Http
179132

180-
type Msg = GotTodo (Result Http.Error Todo)
133+
type Msg =
134+
GotTodo (Result Http.Error Todo)
181135

182136
getTodo : Cmd Msg
183137
getTodo =
@@ -187,7 +141,7 @@ getTodo =
187141
}
188142
```
189143

190-
The function `getTodo` creates a command with HTTP request that expect JSON to be returned and uses `todoDecoder` to get `Todo` type form the returned JSON. Once the request is finished, we get `GotTodo` message containing the `Result` with either `Http.Error` if the request failed or `Todo` if the request was successful.
144+
The function `getTodo` creates a command with HTTP request that expect JSON to be returned and uses `todoDecoder` to get `Todo` type from the returned JSON. Once the request is finished, we get `GotTodo` message containing the `Result` with either `Http.Error` if the request failed or `Todo` if the request was successful.
191145

192146
There are other functions we can use for expected response like `expectString` to get the string as is or `expectWhatever` when we don't really care about the response as long as it's ok.
193147

@@ -196,7 +150,8 @@ When we want to do a POST request we also need to define the body. Here's an exa
196150
```elm
197151
import Http
198152

199-
type Msg = TodoSaved (Result Http.Error ())
153+
type Msg =
154+
TodoSaved (Result Http.Error ())
200155

201156
postTodo : Todo -> Cmd Msg
202157
postTodo todo =
@@ -214,10 +169,10 @@ When we want to do a different type of request than GET and POST or we want to s
214169
```elm
215170
request :
216171
{ method : String
217-
, headers : List Header
172+
, headers : List Http.Header
218173
, url : String
219-
, body : Body
220-
, expect : Expect msg
174+
, body : Http.Body
175+
, expect : Http.Expect msg
221176
, timeout : Maybe Float
222177
, tracker : Maybe String
223178
}
@@ -227,7 +182,7 @@ request :
227182

228183
## Subscriptions
229184

230-
[Subscirptions](https://package.elm-lang.org/packages/elm/core/latest/Platform-Sub) are used to tell Elm that we want to be informed if something happend (e.g., web socket message or clock tick).
185+
[Subscriptions](https://package.elm-lang.org/packages/elm/core/latest/Platform-Sub) are used to tell Elm that we want to be informed if something happend (e.g., web socket message or clock tick).
231186

232187

233188
Here's an example of subscriptions defining that a message `Tick` with current time should be send to update function every 1000 milliseconds.
@@ -237,16 +192,88 @@ Here's an example of subscriptions defining that a message `Tick` with current t
237192
import Time
238193

239194

240-
type Msg = Tick Time.Posix
195+
type alias Model =
196+
()
197+
198+
type Msg =
199+
Tick Time.Posix
241200

242201

243202
subscriptions : Model -> Sub Msg
244203
subscriptions model =
245204
Time.every 1000 Tick
246205
```
247206

207+
## Materials
208+
209+
- [Examples - TODO List](https://github.com/MI-AFP/elm-examples/tree/master/todo)
210+
- [Examples - Timer](https://github.com/MI-AFP/elm-examples/tree/master/timer)
211+
212+
## Further Reading
213+
214+
- [Commands and Subscriptions](https://guide.elm-lang.org/effects/)
215+
- [krisajenkins/remotedata](https://package.elm-lang.org/packages/krisajenkins/remotedata/latest/RemoteData)
216+
- [Elm Europe 2017 - Evan Czaplicki - The life of a file](https://www.youtube.com/watch?v=XpDsk374LDE)
217+
248218

249-
## Random
219+
### Forms
220+
221+
Form elements are created the same way as other HTML elements using functions from [Html](https://package.elm-lang.org/packages/elm/html/latest/Html) module and attributes from [Html.Attributes](https://package.elm-lang.org/packages/elm/html/latest/Html-Attributes) module from [elm/html](https://package.elm-lang.org/packages/elm/html/latest/) package.
222+
223+
We can use `onInput` from [Html.Events](https://package.elm-lang.org/packages/elm/html/latest/Html-Events) module to detect input events and create a message for our update function.
224+
225+
The loop is the following:
226+
- user changes the value in an input field
227+
- a new message is created
228+
- the update function is called with the message and it updates the model with the new value
229+
- input field is re-rendered with the new value
230+
231+
232+
Here is a simple example with a single input field:
233+
234+
```elm
235+
import Browser
236+
import Html exposing (Html)
237+
import Html.Attributes as Attributes
238+
import Html.Events as Events
239+
240+
main : Program () Model Msg
241+
main =
242+
Browser.sandbox
243+
{ init = init
244+
, update = update
245+
, view = view
246+
}
247+
248+
type Msg =
249+
NameChanged String
250+
251+
type alias Model =
252+
{ name : String }
253+
254+
init : Model
255+
init =
256+
{ name = "" }
257+
258+
update : Msg -> Model -> Model
259+
update msg model =
260+
case msg of
261+
NameChanged newName ->
262+
{ model | name = newName }
263+
264+
view : Model -> Html Msg
265+
view model =
266+
Html.input
267+
[ Attributes.placeholder "Your name"
268+
, Attributes.value model.name
269+
, Events.onInput NameChanged ]
270+
[]
271+
```
272+
273+
When we need more complex forms in our application, there are packages to handle forms like [etaque/elm-form](https://package.elm-lang.org/packages/etaque/elm-form/latest/).
274+
275+
276+
### Random
250277

251278
There is a [Random](https://package.elm-lang.org/packages/elm/random/latest/Random) module in [elm/random](https://package.elm-lang.org/packages/elm/random/latest/) package for generating pseudo-random values in Elm. It defines a type called `Generator` which can be think of as a recipe for generating random values.
252279

@@ -283,14 +310,4 @@ import Random exposing (Seed)
283310
generateGrade : Seed -> (Int, Seed)
284311
generateGrade seed =
285312
Random.step randomGrade seed
286-
```
287-
288-
## Materials
289-
290-
- [Examples - TODO List](https://github.com/MI-AFP/elm-examples/tree/master/todo)
291-
- [Examples - Timer](https://github.com/MI-AFP/elm-examples/tree/master/timer)
292-
293-
## Further Reading
294-
295-
- [Commands and Subscriptions](https://guide.elm-lang.org/effects/)
296-
- [Elm Europe 2017 - Evan Czaplicki - The life of a file](https://www.youtube.com/watch?v=XpDsk374LDE)
313+
```

0 commit comments

Comments
 (0)