This is day 4 of my 30 day Elm challenge
Code + demo: https://ellie-app.com/bS7JHCymbpZa1
My only goal today was to publish my three previous Elm projects as interactive web pages - not just their source code.
This was super easy!
- Activate GitHub Pages by going to my GitHub repo's settings, scroll all the way down, and choose
main
as my source. - In each project folder, enter
elm make src/Main.elm
, which creates a big scary HTML file we don't need to worry about. - Push to GitHub.
All subfolders in my repo now have a URL in this format: https://kristianpedersen.github.io/30-days-of-elm/[folder-name]
, showing index.html
if it exists, or readme.md
.
The only downside is that the generated HTML files are thousands of lines long, but they work fine, and there's some interesting and confusing stuff going on in them.
Edit 22nd december 2020: I'm hosting the demos on ellie-app.com instead. The GitHub repo just includes the Elm source code.
Ellie allows you to modify the code and see the result.
GitHub doesn't get filled up with huge HTML files.
Code project: Toggle visibility with checkbox
I wasn't planning to write any code today, but I ended up wanting to anyway.
Today's project is a lot simpler than yesterday's random generator bonanza.
Here's a Svelte example:
<script>
let visible = false
</script>
<input type="checkbox" bind:checked={visible} />
{#if visible}
<p>Hi!</p>
{/if}
Today's code is a lot simpler than yesterday, but I learned a couple of interesting things along the way.
Code walkthrough
- Import and main
- Model
- Update
- View
1. Import and main
module Main exposing (Msg(..), init, main)
import Browser
import Html exposing (Html, div, input, p, text)
import Html.Attributes exposing (checked, type_)
import Html.Events exposing (onCheck)
main : Program () Model Msg
main =
Browser.sandbox { init = init, update = update, view = view }
If you know JavaScript, you might have expected to see a change
event, but Elm calls it onCheck
, which sounds a lot nicer.
https://package.elm-lang.org/packages/elm/html/latest/Html-Events
For the main function, I'm just using Browser.sandbox
rather than Browser.element
, since there's no communicating with external data.
2. Model
type alias Model =
{ visible : Bool
}
init : Model
init =
{ visible = False
}
This could even have been as simple as:
init = False
... but having it as a record makes it easier to add more fields later. Also, the type annotations tend to result in better error messages.
3. Update
type Msg
= ToggleVisibility Bool
update : Msg -> Model -> Model
update msg model =
case msg of
ToggleVisibility checkboxValue ->
{ model | visible = checkboxValue }
Elm events return an Attribute msg
*. I guess that's a user-defined attribute, along with a msg
, which is the event value. But what about the msg
argument in my update function? Is that related to Attribute msg
?
Because I'm a n00b, I was originally going to use onInput
, but I discovered it sends the string representation of event.target.value:
* https://package.elm-lang.org/packages/elm/html/latest/Html-Events
4. View
view : Model -> Html Msg
view model =
div []
[ input [ type_ "checkbox", onCheck ToggleVisibility ] []
, p []
[ if model.visible then
text "Hi!"
else
text ""
]
]
Nothing very fancy here, but I did learn two things about if
statements:
- You have to write
then
- There must be an
else
- Elm needs to have all cases handled, which is something I've heard about in videos before.
Summary
- Deploying simple Elm projects to GitHub Pages is super easy!
- Elm has
onCheck
for checkbox events, instead ofchange
. - Events return an
Attribute msg
, which contains a user-defined attribute and a value from the event target (I guess). - I'm confused by
msg
andAttribute msg
.
Top comments (4)
To answer the confusion around
Attribute msg
,Html msg
, and justmsg
itself. Becausemsg
is lower case it, it means it's a type variable instead of a specific type. In many other languages this would look likeAttribute<T>
,Html<T>
, or justT
. You don't have to use exactlymsg
, you could also writet
ora
, butmsg
is a visual signal to other developers that this should match up with your appsMsg
type.The
Attribute
inAttribute msg
is a HTML attribute, likeid
orname
, andmsg
is used so that you can create attributes which generate amsg
. That's why you haveonCheck : msg -> Atrtibute msg
.Instead of changing the content, you can play with the attribute like this:
module Main exposing (Msg(..), init, main)
import Browser
import Html exposing (Html, div, input, p, text)
import Html.Attributes exposing (checked, type_, style)
import Html.Events exposing (onCheck)
-- Main
main : Program () Model Msg
main =
Browser.sandbox { init = init, update = update, view = view }
-- Model
type alias Model =
{ visible : Bool
, display : String
}
init : Model
init =
{ visible = False
, display = "none"
}
-- Update
type Msg
= ToggleVisibility Bool
update : Msg -> Model -> Model
update msg model =
case msg of
ToggleVisibility checkboxValue ->
{ model | visible = checkboxValue, display = if checkboxValue then "block" else "none" }
-- View
view : Model -> Html Msg
view model =
div []
[ input [ type_ "checkbox", onCheck ToggleVisibility ] []
, p [ style "display" model.display ]
[ text "Hi!" ]
]
Nice! This challenge is fun to follow!
And probably useful for others that are Elm-curious to see it in context of something more familiar like Svelte 🙂
Thanks! I'm having a very good time so far!
The Elm community is really helpful, and I feel that writing really helps me understand the concepts better.
I already have a couple of neat project ideas, so we'll see what tomorrow brings!