Exercise Code for Pragmatic Studio Course Updated for ELM 0.19

_config.yml

(Not an Elm tree by the way)

Front end frameworks are all the rage these days. React! Angular! Ember! Vue! And the new kid on the block is Elm. What will last, and what will be merely passing. Most of these frameworks are backed by the powers that be, the Googles and Facebooks of the world, and a few others are built by a community of die-hards who want to make the computing world a better place. After hearing all this hype and reading reviews, I decided just to try out one, and I settled on ELM.

Pragmatic Studio Are Very Good at Explaining Key Concepts

I like Pragmatic Studio so I went there to learn the basics of ELM. (This is not a paid endorsement of Pragmatic studio courses btw, but having said that, it definitely helped me understand it.) ELM is so fast paced, and since I decided to use ELM 0.19 instead of 0.18 (which is used in the course), some code used in the course is obsolete - it has not been updated to 0.19 (as far as I know). The changes are very small, and nominal, and are easily fixed provided you know how. And if you don’t, well you can spend a lot of time stuffing around. I tried searching online for easy answers, but no buono. Hopefully this will help someone out there doing the course:

module Bingo exposing (..)

import Html exposing (..)
import Html.Attributes exposing(..)
import Html.Events exposing (onClick)
import Browser exposing (sandbox)
import Random exposing (Generator)


-- MODEL
type alias Model = 
    { name: String
    , gameNumber: Int
    , entries: List Entry    
    }

type alias Entry =
    { id: Int
    , phrase: String
    , points: Int
    , marked: Bool
    }


init : () -> (Model, Cmd Msg)
init _ =
    (initialModel, Cmd.none)  


initialModel : Model
initialModel =  
    {name = "Aparna", gameNumber = 1, entries = initalEntries}

initalEntries : List Entry
initalEntries = 
    [ Entry 1 "Back to the" 100 False    
    , Entry 4 "hat is reco" 400 True 
    , Entry 3 "eat movie t" 300 False      
    , Entry 2 "Future a gr" 200 True              
    ]

-- UPDATE
type Msg = NewGame | Mark Int | Sort | NewRandom Int

update : Msg -> Model -> ( Model, Cmd Msg)
update msg model =
    case msg of
        NewRandom randomNumber ->
            ( {model | gameNumber = randomNumber}, Cmd.none)
        NewGame ->
            ( { model | entries = initalEntries }, generateRandomNumber )
        Mark id ->
            let
                markEntry e =
                    if e.id ==id then
                        {e | marked = (not e.marked)}
                    else
                        e                    
            in
                 ({model | entries = List.map markEntry model.entries}, Cmd.none )
                -- List.sortBy .id
        Sort ->
             ({model | entries = List.sortBy .id initalEntries}, Cmd.none )


-- COMMANDS
generateRandomNumber : Cmd Msg
generateRandomNumber = Random.generate NewRandom (Random.int 1 100)


-- VIEW
viewHeader : String -> Html msg
viewHeader title =
    header []
        [h1 [align "center"] [text title]]

viewFooter : Html msg
viewFooter =
    footer []
        [ a [href "https://benkoshy.github.io/"]
            [text "Powered by BBoi"]
        ]

viewPlayer : String -> Int -> Html Msg
viewPlayer name gameNumber =
    let 
        playerInfo =
            name ++ " - Game # is " ++ (String.fromInt gameNumber)           
        playerInfoText  =    
                playerInfo
                |> String.toUpper         
                |> String.pad 100 '*'
                |> Html.text

    in
    Html.h2 [id "info", class "classy"] [ (playerInfoText)]


viewEntryItem : Entry -> Html Msg
viewEntryItem entry = 
    li [ classList [("marked", entry.marked)],   onClick (Mark entry.id) ]
          [ span[ class "phrase"]  [text entry.phrase]
          , span [class "point"] [text (String.fromInt entry.points)]
          ]


viewEntryList : List Entry -> Html Msg
viewEntryList entries =
    let
        listOfEntries = (List.map viewEntryItem entries)            
    in
            
    ul [] listOfEntries

sumMarkedPoints : List Entry -> Int
sumMarkedPoints entries =
    entries
    |> List.filter .marked
    |> List.foldl (\n sum -> sum + n.points) 0 
    {-entries
        |> List.filter .marked
        |> List.map .points
        |> List.sum-}

viewScore : Int -> Html Msg
viewScore sum =
    div 
        [ class "score"]
        [ span [class "label"] [text "Score: "]
        , span [class "value"] [text (Debug.toString sum)]
        ]


view : Model -> Html Msg
view model =
    div [class "content"]
        [viewHeader  "Buzzword Bingo"
        , viewPlayer model.name model.gameNumber
        , viewEntryList model.entries
        , viewScore (sumMarkedPoints model.entries)
        , div [class "btn-group"] 
              [ button [onClick NewGame] [text "New Game"] 
              , button [onClick Sort] [text "Sort"] 
              ]
              
        , div [class "debug"] [text (Debug.toString model)]
        , viewFooter
        ]

main : Program () Model Msg
main =  Browser.element
       { init = init
        , subscriptions = (\_ -> Sub.none)        
        , update = update
        , view = view
       }

You must also updated your elm.json file so that it includes the elm/random package. It wouldn’t work for Elm 0.18 unless it was added in there. This is what I used and it seems to be working fine:

{
    "type": "application",
    "source-directories": [
        "src"
    ],
    "elm-version": "0.19.0",
    "dependencies": {
        "direct": {
            "elm/browser": "1.0.0",
            "elm/core": "1.0.0",
            "elm/html": "1.0.0",
            "elm/random": "1.0.0"
        },
        "indirect": {
            "elm/json": "1.0.0",
            "elm/time": "1.0.0",
            "elm/url": "1.0.0",
            "elm/virtual-dom": "1.0.2"            
        }
    },
    "test-dependencies": {
        "direct": {},
        "indirect": {}
    }
}

When Fetching Data From an API

If you want to install the relevant packages try the following (because the old way shown in the tutorial is obsolete):

elm install elm/http

Other Key Points:

  • toString "Hi, I'm ....." now becomes Debug.toString "Hi, I"m ....."in ELM 0.19.
Written on November 23, 2018