"client/server" communicationElm sends data to JS JS sends data to Elm no direct function calls... Cmd Msgworks with update functions that accept Msg produces messages of type Msg... Cmd
Trang 1@rtfeldman
Trang 28 JavaScript Interop
Trang 3function guarantees
Trang 4same arguments?
no side effects
Trang 5Math.random()
Trang 6localStorage.foo = "bar";
Trang 7access huge JS ecosystem
Trang 8while maintaining guarantees access huge JS ecosystem
Trang 9"client/server" communication
Trang 10Elm sends data to JS
JS sends data to Elm
Trang 11"client/server" communication
Elm sends data to JS
JS sends data to Elm
no direct function calls
Trang 12Cmd on the Elm side
callback on JS side
Trang 13Cmd Msg
Trang 14Cmd msg
Trang 15type variables
Trang 16List.reverse [ "foo", "bar", "baz" ] == [ "baz", "bar", "foo" ]
List.reverse [ 1.1, 2.2, 3.3 ]
== [ 3.3, 2.2, 1.1 ]
List.reverse [ True, False, False ] == [ False, False, True ]
Trang 17reverse :
Trang 18reverse : List ??? -> List ???
Trang 19reverse : List val -> List val
Trang 20reverse : List val -> List val
type variable
Trang 21reverse : List val -> List val
reverse : List thing -> List thing
reverse : List a -> List a
Trang 22elmHubHeader : Html Msg
elmHubHeader =
header []
[ h1 [] [ text "ElmHub" ]
, span [ class "tagline" ]
[ text "Like GitHub " ] ]
Trang 23elmHubHeader : Html Msg
elmHubHeader =
header []
[ h1 [] [ text "ElmHub" ]
, span [ class "tagline" ]
[ text "Like GitHub " ] ]
"this is compatible with Html that produces Msg"
Trang 24elmHubHeader : Html msg
elmHubHeader =
header []
[ h1 [] [ text "ElmHub" ]
, span [ class "tagline" ]
[ text "Like GitHub " ] ]
Trang 25elmHubHeader : Html a
elmHubHeader =
header []
[ h1 [] [ text "ElmHub" ]
, span [ class "tagline" ]
[ text "Like GitHub " ] ]
Trang 26Cmd Msg
produces messages of type Msg
Trang 27Cmd Msg
works with update functions that accept Msg
produces messages of type Msg
Trang 28Cmd Msg
Cmd msg
works with any update function
Trang 29Cmd Msg
Cmd msg
works with any update function
because it never produces any messages!
Trang 30the port keyword
&
index.html
Trang 31subscriptions
Trang 32view update
Elm Runtime
Cmd Msg
Model
Trang 33view update
Elm Runtime
Cmd Msg Model
subscriptions
Trang 34view update
Elm Runtime
Cmd Msg Model
subscriptions Msg
Trang 35view update
Trang 36github.js
Trang 37Exercise: resolve the TODOs in part8
decodeString responseDecoder json
decodeValue responseDecoder json
Trang 389 Testing
Trang 39"version": "1.0.0",
"summary": "Like GitHub, but for Elm stuff.",
"repository": "https://github.com/rtfeldman/elm-workshop.git", "license": "BSD-3-Clause",
Trang 40"version": "1.0.0",
"summary": "Like GitHub, but for Elm stuff.",
"repository": "https://github.com/rtfeldman/elm-workshop.git", "license": "BSD-3-Clause",
Trang 41"version": "1.0.0",
"summary": "Like GitHub, but for Elm stuff.",
"repository": "https://github.com/rtfeldman/elm-workshop.git", "license": "BSD-3-Clause",
Trang 42elm-package.json Main.elm
ElmHub.elm
Trang 43"version": "1.0.0",
"summary": "Like GitHub, but for Elm stuff.",
"repository": "https://github.com/rtfeldman/elm-workshop.git", "license": "BSD-3-Clause",
Trang 44"version": "1.0.0",
"summary": "Like GitHub, but for Elm stuff.",
"repository": "https://github.com/rtfeldman/elm-workshop.git", "license": "BSD-3-Clause",
Trang 45"version": "1.0.0",
"summary": "Like GitHub, but for Elm stuff.",
"repository": "https://github.com/rtfeldman/elm-workshop.git", "license": "BSD-3-Clause",
Trang 46"NoRedInk/elm-decode-pipeline": "1.1.2 <= v < 2.0.0"
Trang 50major minor patch
Trang 51"NoRedInk/elm-decode-pipeline": "1.1.2 <= v < 2.0.0"
1.1.2 major minor patch
semantic versioning automatically enforced
Trang 52elm-package.json Main.elm
ElmHub.elm
Trang 53Tests.elm
Trang 54"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0",
"rtfeldman/html-test-runner": "1.0.0 <= v < 2.0.0", "rtfeldman/node-test-runner": "2.0.0 <= v < 3.0.0"
}
tests/elm-package.json
tests
Trang 55"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0",
"rtfeldman/html-test-runner": "1.0.0 <= v < 2.0.0", "rtfeldman/node-test-runner": "2.0.0 <= v < 3.0.0"
}
tests/elm-package.json
tests main source
Trang 56"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0",
"rtfeldman/html-test-runner": "1.0.0 <= v < 2.0.0", "rtfeldman/node-test-runner": "2.0.0 <= v < 3.0.0"
}
tests/elm-package.json
Trang 57"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0",
"rtfeldman/html-test-runner": "1.0.0 <= v < 2.0.0", "rtfeldman/node-test-runner": "2.0.0 <= v < 3.0.0"
}
tests/elm-package.json
Trang 58package.elm-lang.org
Trang 59unit tests
Trang 60"[ 1, 2, 3 ]"
|> decodeString (list int)
|> Expect.equal (Ok [ 1, 2, 3])
Trang 62\throwawayArgument ->
"[ 1, 2, 3 ]"
|> decodeString (list int)
|> Expect.equal (Ok [ 1, 2, 3])
Trang 63() empty tuple, aka "Unit"
\throwawayArgument ->
"[ 1, 2, 3 ]"
|> decodeString (list int)
|> Expect.equal (Ok [ 1, 2, 3])
Trang 64\() ->
"[ 1, 2, 3 ]"
|> decodeString (list int)
|> Expect.equal (Ok [ 1, 2, 3])
Trang 65test "it successfully decodes" (
Trang 66[ 2, 4, 6, 8 ]
|> List.filter (\num -> num < 5)
|> List.reverse
Trang 68[ 2, 4, 6, 8 ] |> List.filter (\num -> num < 5) |> List.reverse
List.reverse (List.filter (\num -> num < 5) [ 2, 4, 6, 8 ])
List.reverse <| List.filter (\num -> num < 5) [ 2, 4, 6, 8 ]
Trang 69test "it successfully decodes" (
Trang 70test "it successfully decodes" <|
\() ->
"[ 1, 2, 3 ]"
|> decodeString (list int)
|> Expect.equal (Ok [ 1, 2, 3])
Trang 71describe "decoder tests"
[ test "it successfully decodes" <|
Trang 72describe "all my tests"
[ describe "decoder tests"
[ test "it successfully decodes" <|
\() ->
"[ 1, 2, 3 ]"
|> decodeString (list int)
|> Expect.equal (Ok [ 1, 2, 3]) ]
]
Trang 73test "Reversing twice does nothing" <| \() ->
[ 1, 2, 3 ]
|> List.reverse
|> List.reverse
|> Expect.equal [ 1, 2, 3 ]
Trang 74fuzz int "Reversing twice does nothing" <|
Trang 75fuzz (list int) "Reversing twice does nothing" <| \randomList ->
randomList
|> List.reverse
|> List.reverse
|> Expect.equal randomList
Trang 76fuzz2 int float "Integers are bigger than floats" <| \randomInt randomFloat- >
randomInt
|> Expect.greaterThan randomFloat
Trang 77fuzz2 int float "Integers are bigger than floats" <| \randomInt randomFloat->
randomInt
|> Expect.greaterThan randomFloat
Exercise: resolve the TODOs in part9
test "it decodes successfully" <|
\() ->
"[ 1, 2, 3 ]"
|> decodeString (list int) |> Expect.equal (Ok [ 1, 2, 3])
Trang 7810 Delegation
Trang 79Adding Search Options
Trang 80searchIn userFilter minStars
Trang 81type Msg = Search | SetQuery String | DeleteById Int
| SetMinStars Int | SetSearchIn String | SetUserFilter String
type alias Model =
{ query : String
, results : List SearchResult
, errorMessage : Maybe String
, minStars : Int
, searchIn : String
, userFilter : String
}
Trang 82type Msg = Search | SetQuery String | DeleteById Int
| SetMinStars String
| SetSearchIn String | SetUserFilter String
type alias Model =
{ query : String
, results : List SearchResult
, errorMessage : Maybe String
Trang 83type Msg = Search | SetQuery String | DeleteById Int | SetMinStars String | SetSearchIn String | SetUserFilter String
type alias Model =
{ query : String
, results : List SearchResult
, errorMessage : Maybe String
Trang 84type Msg = Search | SetQuery String | DeleteById Int | SetMinStars String | SetSearchIn String | SetUserFilter String
type alias Model =
{ query : String
, results : List SearchResult
, errorMessage : Maybe String
Trang 85type Msg = Search | SetQuery String | DeleteById Int | SetMinStars String | SetSearchIn String | SetUserFilter String
type alias Model =
{ query : String
, results : List SearchResult
, errorMessage : Maybe String
Trang 86type Msg = Search | SetQuery String | DeleteById Int | SetMinStars String | SetSearchIn String | SetUserFilter String
type alias Model =
{ query : String
, results : List SearchResult
, errorMessage : Maybe String
Trang 87type Msg = Search | SetQuery String | DeleteById Int | SetMinStars String | SetSearchIn String | SetUserFilter String
type alias Model =
{ query : String
, results : List SearchResult
, errorMessage : Maybe String
Trang 88type Msg = Search | SetQuery String | DeleteById Int | SetMinStars String | SetSearchIn String | SetUserFilter String
type alias Model =
{ query : String
, results : List SearchResult
, errorMessage : Maybe String
Trang 89type Msg = Search | SetQuery String | DeleteById Int | SetMinStars String | SetSearchIn String | SetUserFilter String
type alias Model =
{ query : String
, results : List SearchResult
, errorMessage : Maybe String
Trang 90type Msg = Search | SetQuery String | DeleteById Int
type OptionsMsg = SetMinStars String | SetSearchIn String | SetUserFilter String
type alias Model =
{ query : String
, results : List SearchResult
, errorMessage : Maybe String
Trang 91type Msg = Search | SetQuery String | DeleteById Int | Options OptionsMsg
type OptionsMsg = SetMinStars String | SetSearchIn String | SetUserFilter String
type alias Model =
{ query : String
, results : List SearchResult
, errorMessage : Maybe String
Trang 92type Msg = Search | SetQuery String | DeleteById Int | Options OptionsMsg
type OptionsMsg = SetMinStars String | SetSearchIn String | SetUserFilter String
type alias Model =
{ query : String
, results : List SearchResult
, errorMessage : Maybe String
Trang 93type Msg = Search | SetQuery String | DeleteById Int | Options OptionsMsg
type OptionsMsg = SetMinStars String | SetSearchIn String | SetUserFilter String
type alias Model =
{ query : String
, results : List SearchResult
, errorMessage : Maybe String
Trang 94type OptionsMsg = SetMinStars String | SetSearchIn String | SetUserFilter String
type alias SearchOptions =
Trang 95type OptionsMsg = SetMinStars String | SetSearchIn String | SetUserFilter String
type alias SearchOptions =
viewOptions : SearchOptions -> Html OptionsMsg
input [] [ value model.options.sort, onInput (Options SetSort) ]
Trang 96viewOptions : SearchOptions -> Html OptionsMsg
viewOptions options =
input [] [ value options.sort, onInput SetSort ]
Trang 97viewOptions : SearchOptions -> Html OptionsMsg
view : Model -> Html Msg
view model =
div [ class "content" ]
[ input [ defaultValue model.query, onInput SetQuery ] [] , button [ onClick Search ] [ text "Search" ]
]
Trang 98viewOptions : SearchOptions -> Html OptionsMsg
view : Model -> Html Msg
view model =
div [ class "content" ]
[ input [ defaultValue model.query, onInput SetQuery ] [] , button [ onClick Search ] [ text "Search" ]
]
Trang 99view : Model -> Html Msg
view model =
div [ class "content" ]
[ input [ defaultValue model.query, onInput SetQuery ] [] , button [ onClick Search ] [ text "Search" ]
]
viewOptions : SearchOptions -> Html OptionsMsg
Trang 100view : Model -> Html Msg
view model =
div [ class "content" ]
[ input [ defaultValue model.query, onInput SetQuery ] [] , button [ onClick Search ] [ text "Search" ]
]
List String List Int
viewOptions : SearchOptions -> Html OptionsMsg
Trang 101view : Model -> Html Msg
view model =
div [ class "content" ]
[ input [ defaultValue model.query, onInput SetQuery ] [] , button [ onClick Search ] [ text "Search" ]
]
List String
viewOptions : SearchOptions -> Html OptionsMsg
Trang 102view : Model -> Html Msg
view model =
div [ class "content" ]
[ input [ defaultValue model.query, onInput SetQuery ] []
, button [ onClick Search ] [ text "Search" ]
]
List String
String.length : String -> Int
viewOptions : SearchOptions -> Html OptionsMsg
Trang 103view : Model -> Html Msg
view model =
div [ class "content" ]
[ input [ defaultValue model.query, onInput SetQuery ] []
, button [ onClick Search ] [ text "Search" ]
]
Html String
String.length : String -> Int
viewOptions : SearchOptions -> Html OptionsMsg
Trang 104view : Model -> Html Msg
view model =
div [ class "content" ]
[ input [ defaultValue model.query, onInput SetQuery ] []
, button [ onClick Search ] [ text "Search" ]
]
Html String
String.length : String -> Int
viewOptions : SearchOptions -> Html OptionsMsg
Trang 105Html OptionsMsg
Html Msg
Trang 106Html OptionsMsg
Html.map
Html Msg
Trang 107Html OptionsMsg
Html.map ???
Html Msg
Trang 108Html OptionsMsg OptionsMsg -> Msg
Html.map ???
Html Msg
Trang 109type Msg = Search | SetQuery String | DeleteById Int | Options OptionsMsg
Html OptionsMsg OptionsMsg -> Msg Html.map ???
Html Msg
Trang 110type Msg = Search | SetQuery String | DeleteById Int | Options OptionsMsg
Html OptionsMsg OptionsMsg -> Msg Html.map ???
Html Msg
Trang 111viewOptions : SearchOptions -> Html OptionsMsg
view : Model -> Html Msg
view model =
div [ class "content" ]
[ input [ defaultValue model.query, onInput SetQuery ] [] , button [ onClick Search ] [ text "Search" ]
]
Trang 112viewOptions : SearchOptions -> Html OptionsMsg
view : Model -> Html Msg
view model =
div [ class "content" ]
[ input [ defaultValue model.query, onInput SetQuery ] [] , button [ onClick Search ] [ text "Search" ]
, viewOptions model.options
]