【问题标题】:How to update specific element in a list in Elm如何更新 Elm 列表中的特定元素
【发布时间】:2022-01-01 16:42:22
【问题描述】:

有一对applesList 类型)将在网络视图中公开他们自己。用户可以更新Apple 的任何size 属性。我有一个消息类型UpdateSize,它将通过onInput 触发。

编辑任何苹果只会触发消息而不知道要更新哪个苹果。

是否可以将id 属性传递给UpdateSize 消息?

感谢您阅读本文,Elm 很棒!

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
        }

代码链接:https://ellie-app.com/ghd9jrcjKQQa1

【问题讨论】:

  • 请将所有相关代码放入问题本身。到 ellie 的链接很棒,但它应该是补充的。问题应该是独立的,这样即使外部资源被取消,它们仍然有意义。
  • 至于你的问题,你怎么知道哪个苹果是哪个?确定 this apple 与 that apple 不同的属性或属性集是什么?
  • @glennsl 谢谢。我用apple做demo,我用size只是demo,不过也可以换成apple的name,应该是唯一的。
  • 我想了这么多,我的意思是,通过删除属性,您也删除了识别要更新的特定项目的方式。当然,您可以只使用列表索引,但在现实世界中,这通常是一个站不住脚的有缺陷的假设。例如,如果您要对视图中的项目进行排序或过滤,则索引将是错误的,您只能通过观察意外行为来判断。除非在其他地方确保名称的唯一性等,否则使用 name 属性很容易出现重复。重点是:数据很重要。

标签: elm


【解决方案1】:

使用您当前的实现,由于没有关于苹果的唯一属性,因此无法知道要更新哪个苹果。如果两个苹果大小一样怎么办?如果苹果有 ID 会更好,或者您使用字典类型来跟踪苹果。

但是,为了演示,您可以说苹果的列表索引是唯一的,您可以相应地找到它们。在现实生活中,这将是一个脆弱的解决方案。

这是使用来自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)

【讨论】:

    猜你喜欢
    • 2016-04-02
    • 1970-01-01
    • 2017-07-31
    • 1970-01-01
    • 2021-10-30
    • 2021-12-04
    • 2020-04-07
    • 2021-12-25
    • 1970-01-01
    相关资源
    最近更新 更多