There are couple apples
( in type of List
) which will expose themselvies in the web view. User can update any size
attribute of an Apple
. I have a msg type UpdateSize
which will be triggered via onInput
.
Editing any of the apples will only just trigger the message without knowing which apple to be updated.
Is that possible to pass an id
attribute to UpdateSize
message?
Thank you for reading this, Elm is great !
module Main exposing (main)
import Browser
import Html exposing (Html, button, div, text, input)
import Html.Attributes exposing (..)
import Html.Events exposing (onClick,onInput)
import String
type alias Apple = {
size: Int}
type alias Model = {
apples: List(Apple)}
initialModel : Model
initialModel =
{ apples = [ Apple 10, Apple 11, Apple 12] }
type Msg
= UpdateSize String
update : Msg -> Model -> Model
update msg model =
case msg of
UpdateSize s -> {model | apples = ??? } -- how to update a single Apple with new size
_ -> model
viewApple : Apple -> Html Msg
viewApple a =
input [ type_ "text" ,placeholder ""
, value (String.fromInt a.size)
, onInput UpdateSize]
[]
view : Model -> Html Msg
view model =
div []
(List.map viewApple model.apples)
main : Program () Model Msg
main =
Browser.sandbox
{ init = initialModel
, view = view
, update = update
}
Code link: https://ellie-app.com/ghd9jrcjKQQa1
With your current implementation it's not possible to know which apple to update since there's no unique attribute about the apples. What if two apples have the same size? If would be better if apples had IDs, or you used a dictionary type to keep track of the apples.
However, for the sake of demonstration, you could say that the list indeces of the apples are unique and you find them accordingly. In real life this will be a fragile solution.
Here's a naive approach using some helper functions from List.Extra
.
-- ...
type alias Size =
Int
type Msg
= UpdateSize Int String
update : Msg -> Model -> Model
update msg model =
case msg of
UpdateSize index sizeStr ->
let
maybeSize =
String.toInt sizeStr
in
maybeSize
|> Maybe.withDefault (\size -> { model | apples = updateApple index size model.apples })
|> model
_ ->
model
updateApple : Int -> Size -> List Apple -> List Apple
updateApple index size apples =
let
maybeApple =
List.Extra.getAt index apples
in
maybeApple
|> Maybe.map (\apple -> List.Extra.setAt index { apple | size = size } apples)
|> Maybe.withDefault apples
-- ...
viewApple : Int -> Apple -> Html Msg
viewApple index a =
input
[ type_ "text"
, placeholder ""
, value (String.fromInt a.size)
, onInput (UpdateSize index)
]
[]
view : Model -> Html Msg
view model =
div []
(List.indexedMap viewApple model.apples)