我正在尝试在我的更新功能中更新我的List Token
模型中的比特币价格字段。这是我的代码我似乎无法让它只更新价格字段。我是否需要访问列表元素,因为我的模型是列表?这可以在elm中使用记录语法吗?
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Bass exposing (style, center, h1)
import Http
import Json.Decode as Decode
main =
Html.program
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
------------- MODEL
type alias Model =
{ tokens : List Token
}
init : (Model, Cmd Msg)
init =
(initialModel , Cmd.none)
initialModel : Model
initialModel =
{ tokens = [Token "Bitcoin" "150" "11000.00"]
}
type alias Token =
{ name : String
, holdings : String
, price : String
}
------------- UPDATE
type Msg
= FetchDatabasePrice | FetchLivePrice (Result Http.Error String)
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
FetchDatabasePrice ->
(model, getPrice )
FetchLivePrice (Ok newPrice) ->
( { model | price = newPrice }, Cmd.none )
FetchLivePrice (Err _) ->
(model,Cmd.none)
getPrice : Cmd Msg
getPrice =
let
url = "https://api.coinmarketcap.com/v1/ticker/bitcoin/"
request = Http.get url decodedUrl
in
Http.send FetchLivePrice request
decodedUrl : Decode.Decoder String
decodedUrl = Decode.at ["price_usd"] Decode.string
------------- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none
------------- VIEW
view : Model -> Html Msg
view model =
div []
[nav
, div [] [list model.tokens]
, div [] [ button [onClick (FetchDatabasePrice) ] [text "Fetch Price"] ]
]
------BROKEN INTO PIECES---------
nav : Html Msg
nav = div [Bass.style
[center
, Bass.h1
, [("background-color", "black")
, ("color", "white")
]
]
]
[ div [] [text "Crypto Nutshell"]]
list : List Token -> Html Msg
list tokens =
div [Bass.style
[Bass.left_align
]
]
[div [ class "p1"]
[ table []
[ thead []
[ tr []
[ th [] [text "Name"]
, th [] [text "Holdings"]
, th [] [text "Price"]
, th [] [text "Actions"]
]
]
, tbody [] (List.map tokenRow tokens)
]
]
]
tokenRow : Token -> Html Msg
tokenRow token =
tr []
[ td [] [ text token.name ]
, td [] [ text token.holdings ]
, td [] [ text token.price ]
]
这是我的错误:
-- TYPE MISMATCH ------------------------------------------------------ test.elm
The definition of `update` does not match its type annotation.
50| update : Msg -> Model -> (Model, Cmd Msg)
51| update msg model =
52|> case msg of
53|> FetchDatabasePrice ->
54|> (model, getPrice )
55|> FetchLivePrice (Ok newPrice) ->
56|> ( { model | price = newPrice }, Cmd.none )
57|> FetchLivePrice (Err _) ->
58|> (model,Cmd.none)
The type annotation for `update` says it always returns:
( Model, Cmd Msg )
But the returned value (shown above) is a:
( { b | price : String }, Cmd Msg )
Hint: The record fields do not match up. One has tokens. The other has price.
-- TYPE MISMATCH ------------------------------------------------------ test.elm
`model` is being used in an unexpected way.
56| ( { model | price = newPrice }, Cmd.none )
^^^^^
Based on its definition, `model` has this type:
Model
But you are trying to use it as:
{ b | price : a }
Hint: The record fields do not match up. One has tokens. The other has price.
答案 0 :(得分:4)
类型错误从根本上告诉您您的问题 - 您正在尝试使用Token
,但您没有 - 您有Model
。
我们如何从一个到另一个?好。我们从模型开始,我们可以model.tokens
获得List Token
。然后,我们想要修改该列表以包含更新的新标记。正常的方法是使用List.map。这适用于每个Token
并提供更新列表。遵循以下步骤:
FetchLivePrice (Ok newPrice) ->
let
updatePrice = (\token -> { token | price = newPrice })
updated = List.map updatePrice model.tokens
in
({ model | tokens = updated }, Cmd.none )
现在,我给出的解决方案是一个简单的解决方案,当你有多个不同的令牌时它们会崩溃(它们会同时被改变)。由于你现在只有一个,只需简化模型只采用一个令牌而不是列表就可以实现同样的目的。
如果您希望能够使用具有多个令牌的功能,则需要开始识别您获得价格的令牌,以便更新正确的令牌。
实际上,你可能希望这最终看起来像:
FetchLivePrice tokenId (Ok newPrice) ->
({ model | tokens = tokenUpdatePrice tokenId newPrice model.tokens, Cmd.none)
其中tokenUpdatePrice
是一个操作列表的函数(或其他数据结构 - 字典可能是合适的,尽管您可能需要存储单独的演示顺序)来更新相应的记录。 tokenId
将用于标识令牌。