Search code examples
recordelm

Update record field from Collection


I am playing a little bit with Elm these days, but I stuck with a simple case where I want to update a record field. My code is like this:

-- MODEL


initialModel : Model
initialModel =
    { selectedLanguage = "german"
    , allCards = Card.cards
    }


type alias Msg =
    { description : String
    , data : String
    , id : String
    }

The update function

update : Msg -> Model -> Model
update msg model =
    case List.head (model.allCards) of
        Just card ->
            { card | fliped = True }
        Nothing -> model

but I see this:

Something is off with the 1st branch of this `case` expression:

50|             { card | fliped = True }
                ^^^^^^^^^^^^^^^^^^^^^^^^
The 1st branch is a record of type:

    { back : String, fliped : Bool, front : String, id : String }

But the type annotation on `update` says it should be:

    Model

Hint: Seems like a record field typo. Maybe back should be allCards?

Hint: Can more type annotations be added? Type annotations always help me give
more specific messages, and I think they could help a lot in this case!
Detected errors in 1 module.

I think I should always return a model from update function like my type says, but cannot figure out how. Any advice here?


Solution

  • You'll have update the allCards field of model too. You can nest the card update inside the model update if the former returns a list instead of just a single card:

    update : Msg -> Model -> Model
    update msg model =
        { model
        | allCards =
            case model.allCards of
                card :: rest ->
                    { card | fliped = True } :: rest
    
                [] ->
                    []
        }
    

    Or you can bind the new allCards to a name if you prefer:

    update : Msg -> Model -> Model
    update msg model =
        let
            newAllCards =
                case model.allCards of
                    card :: rest ->
                        { card | fliped = True } :: rest
    
                    [] ->
                        []
        in
        { model | allCards = newAllCards }
    

    I pattern match directly on the list here instead of using List.head, as that also gives me the remainder of the list and I don't have to deal with an intermediary Maybe value (or two actually, since List.tail returns a Maybe as well). The card::rest branch hits if allCards contains at least one card, so the only remaining case is therefore [], which is easy enough to handle.

    Also, flipped is spelled with two ps ;)