使用elm进行HTTP调用以修改数据
如图所示,我创建了一个小示例程序,其中有一些控件可以修改模型的某些部分 我一直试图做的是发出一个HTTP请求以获取初始数据(它现在是硬编码的),或者稍后在收到重置消息时用来自所述HTTP请求的响应替换数据,但没有成功。我确实读过《榆树简介》,但我似乎无法把事情拼凑起来 我们的目标是拥有一个loadTraits函数,它接受一个字符串(SomeId)并返回一个TraitWithRelevance类型的列表,这样我就可以用传入的数据替换模型使用elm进行HTTP调用以修改数据,elm,Elm,如图所示,我创建了一个小示例程序,其中有一些控件可以修改模型的某些部分 我一直试图做的是发出一个HTTP请求以获取初始数据(它现在是硬编码的),或者稍后在收到重置消息时用来自所述HTTP请求的响应替换数据,但没有成功。我确实读过《榆树简介》,但我似乎无法把事情拼凑起来 我们的目标是拥有一个loadTraits函数,它接受一个字符串(SomeId)并返回一个TraitWithRelevance类型的列表,这样我就可以用传入的数据替换模型 module Main exposing (..) im
module Main exposing (..)
import Html exposing (Html, button, div, text, input, ul, img)
import Html.Attributes as Attr
import Html.Events exposing (onClick, onInput)
import Http exposing (..)
import Json.Decode as Decode
main =
Html.program
{ init = init
, view = view
, update = update
, subscriptions = \_ -> Sub.none
}
-- MODEL
type alias ContentWithTraits =
{ someId : SomeId
, traits : List TraitWithRelevance
}
type alias MetaInfo =
{ name : String
, imageUrl : String
}
type alias Name =
String
type alias SomeId =
String
type alias Relevance =
String
type alias TraitWithRelevance =
( Name, SomeId, Relevance )
type TraitToAdd
= Nothing
| TraitWithRelevance
type alias Model =
{ contentWithTraits : ContentWithTraits
, metaInfo : MetaInfo
, traitToAdd : TraitToAdd
}
init : ( Model, Cmd Msg )
init =
( Model contentWithTraits { name = "content name", imageUrl = "http://weknowmemes.com/generator/uploads/generated/g1369409960206058073.jpg" } Nothing, Cmd.none )
contentWithTraits : ContentWithTraits
contentWithTraits =
{ someId = "some default id"
, traits =
[ ( "name for trait a", "a", "1" )
, ( "this is the name for trait b", "b", "50" )
]
}
-- UPDATE
type Msg
= EditTrait SomeId Relevance
| Reset
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
EditTrait someId relevance ->
let
_ =
Debug.log "model: " model
in
( replaceTraits model <| List.map (updateTrait ( someId, relevance ))
, Cmd.none
)
Reset ->
-- ( replaceTraits model <| loadTraits model.contentWithTraits.someId, Cmd.none )
{-
NOTE: I'm stuck here...
should make HTTP GET request, then replace the model.contentWithTraits.traits with the decoded JSON's traits field
-}
( model, Cmd.none )
replaceTraits : Model -> (List TraitWithRelevance -> List TraitWithRelevance) -> Model
replaceTraits model func =
{ model
| contentWithTraits =
{ someId = model.contentWithTraits.someId
, traits = func model.contentWithTraits.traits
}
}
updateTrait : ( SomeId, Relevance ) -> TraitWithRelevance -> TraitWithRelevance
updateTrait updatedTrait originalTrait =
let
( name, someId, _ ) =
originalTrait
( someIdVerification, newValue ) =
updatedTrait
_ =
Debug.log "updatedTrait: " updatedTrait
in
if someId == someIdVerification then
( name, someId, newValue )
else
originalTrait
-- VIEW
valueRange : String -> TraitWithRelevance -> Html Msg
valueRange typ trait =
let
( name, someId, relevance ) =
trait
in
input [ Attr.type_ typ, Attr.min <| toString 0, Attr.max <| toString 100, Attr.value relevance, Attr.step <| toString 1, onInput <| EditTrait someId ] []
traitView : TraitWithRelevance -> Html Msg
traitView trait =
let
( name, someId, relevance ) =
trait
in
div []
[ text someId
, valueRange "range" trait
, valueRange "number" trait
, text name
]
view : Model -> Html Msg
view model =
div []
[ text model.contentWithTraits.someId
, img [ Attr.src model.metaInfo.imageUrl, Attr.width 300 ] []
, ul [] (List.map traitView model.contentWithTraits.traits)
, button [ onClick Reset ] [ text "Reset" ]
]
另外,尽管有很多行代码,但请注意,我在保持足够的上下文的同时,尽可能地消除了问题。您需要一条返回数据的消息。假设它是一个简单的
Trait
s列表:
type Msg
= EditTrait SomeId Relevance
| Reset
| OnFetchTraits (Result Http.Error (List Traits))
然后需要一个命令来发送请求,比如
fetchTraits : Cmd Msg
fetchTraits =
Http.get "http://localhost:4000/traits" traitListDecoder
|> Http.send OnFetchTraits
您需要实现traitListDecoder
,将JSON解码到msg中返回的列表中
然后,您将返回
fetchTraits
,而不是在被卡住的update
函数中返回Cmd.none
。然后Elm将发出请求,您将得到一个OnFetchTraits
msg,并将其传递到update
。你需要一个单独的案例来处理这个问题。如果请求成功,您可以解压缩结果
类型并提取数据;如果请求不成功,您可以处理错误。您需要一条返回数据的消息。假设它是一个简单的Trait
s列表:
type Msg
= EditTrait SomeId Relevance
| Reset
| OnFetchTraits (Result Http.Error (List Traits))
然后需要一个命令来发送请求,比如
fetchTraits : Cmd Msg
fetchTraits =
Http.get "http://localhost:4000/traits" traitListDecoder
|> Http.send OnFetchTraits
您需要实现traitListDecoder
,将JSON解码到msg中返回的列表中
然后,您将返回
fetchTraits
,而不是在被卡住的update
函数中返回Cmd.none
。然后Elm将发出请求,您将得到一个OnFetchTraits
msg,并将其传递到update
。你需要一个单独的案例来处理这个问题。如果请求成功,您可以解压结果
类型并提取数据;如果请求失败,您可以处理错误。因此,基本上您需要做两件事,重置按钮应该调用命令来获取特征。然后,在更新中,您必须处理来自命令的响应。返回结果后,可以使用它更新模型
这是对您的代码的更新。我在模型中添加了一个人,当用户按下重置按钮时,这个人会得到更新
module Main exposing (..)
import Html exposing (Html, button, div, text, input, ul, img)
import Html.Attributes as Attr
import Html.Events exposing (onClick, onInput)
import Http exposing (..)
import Json.Decode exposing (Decoder, string)
import Json.Decode.Pipeline exposing (decode, required)
main =
Html.program
{ init = init
, view = view
, update = update
, subscriptions = \_ -> Sub.none
}
-- Commands
type alias Person =
{ name : String
, gender : String
}
decodePerson : Decoder Person
decodePerson =
decode Person
|> required "name" string
|> required "gender" string
getTraits =
let
url =
"http://swapi.co/api/people/1/"
request =
Http.get url decodePerson
in
Http.send GetTraitResponse request
-- MODEL
type alias ContentWithTraits =
{ someId : SomeId
, traits : List TraitWithRelevance
}
type alias MetaInfo =
{ name : String
, imageUrl : String
}
type alias Name =
String
type alias SomeId =
String
type alias Relevance =
String
type alias TraitWithRelevance =
( Name, SomeId, Relevance )
type TraitToAdd
= Nothing
| TraitWithRelevance
type alias Model =
{ contentWithTraits : ContentWithTraits
, metaInfo : MetaInfo
, traitToAdd : TraitToAdd
, person : Person
}
init : ( Model, Cmd Msg )
init =
( Model contentWithTraits { name = "content name", imageUrl = "http://weknowmemes.com/generator/uploads/generated/g1369409960206058073.jpg"} Nothing {name = "", gender=""}, Cmd.none )
contentWithTraits : ContentWithTraits
contentWithTraits =
{ someId = "some default id"
, traits =
[ ( "name for trait a", "a", "1" )
, ( "this is the name for trait b", "b", "50" )
]
}
-- UPDATE
type Msg
= EditTrait SomeId Relevance
| GetTraitResponse (Result Http.Error Person)
| Reset
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
EditTrait someId relevance ->
let
_ =
Debug.log "model: " model
in
( replaceTraits model <| List.map (updateTrait ( someId, relevance ))
, Cmd.none
)
-- handle the response
GetTraitResponse resp ->
let
_ =
Debug.log "response" resp
person =
case resp of
Ok val ->
val
Result.Err e ->
{name = "", gender=""}
in
( {model | person = person }, Cmd.none )
Reset ->
-- ( replaceTraits model <| loadTraits model.contentWithTraits.someId, Cmd.none )
{-
NOTE: I'm stuck here...
should make HTTP GET request, then replace the model.contentWithTraits.traits with the decoded JSON's traits field
-}
-- call the command to get the traits
( model, getTraits )
replaceTraits : Model -> (List TraitWithRelevance -> List TraitWithRelevance) -> Model
replaceTraits model func =
{ model
| contentWithTraits =
{ someId = model.contentWithTraits.someId
, traits = func model.contentWithTraits.traits
}
}
updateTrait : ( SomeId, Relevance ) -> TraitWithRelevance -> TraitWithRelevance
updateTrait updatedTrait originalTrait =
let
( name, someId, _ ) =
originalTrait
( someIdVerification, newValue ) =
updatedTrait
_ =
Debug.log "updatedTrait: " updatedTrait
in
if someId == someIdVerification then
( name, someId, newValue )
else
originalTrait
-- VIEW
valueRange : String -> TraitWithRelevance -> Html Msg
valueRange typ trait =
let
( name, someId, relevance ) =
trait
in
input [ Attr.type_ typ, Attr.min <| toString 0, Attr.max <| toString 100, Attr.value relevance, Attr.step <| toString 1, onInput <| EditTrait someId ] []
traitView : TraitWithRelevance -> Html Msg
traitView trait =
let
( name, someId, relevance ) =
trait
in
div []
[ text someId
, valueRange "range" trait
, valueRange "number" trait
, text name
]
view : Model -> Html Msg
view model =
div []
[ text model.contentWithTraits.someId
, img [ Attr.src model.metaInfo.imageUrl, Attr.width 300 ] []
, ul [] (List.map traitView model.contentWithTraits.traits)
, button [ onClick Reset ] [ text "Reset" ]
, text <| toString model
]
模块主显示(…)
导入Html(Html、按钮、div、文本、输入、ul、img)
将Html.Attributes作为Attr导入
导入Html.Events(onClick,onInput)
导入Http公开(…)
导入Json.Decode(解码器,字符串)
导入Json.Decode.Pipeline(解码,必需)
主要=
Html.program
{init=init
,视图=视图
,update=update
,订阅=\ \->Sub.none
}
--命令
类型别名Person=
{name:String
,性别:String
}
解码人:解码人
解码人=
解码人
|>必需的“名称”字符串
|>必需的“性别”字符串
盖特雷茨=
让
网址=
"http://swapi.co/api/people/1/"
请求=
Http.get-url-decodePerson
在里面
Http.send GetTraitResponse请求
--模型
键入别名ContentWithTraits=
{someId:someId
,traits:List TraitWithRelevance
}
类型别名MetaInfo=
{name:String
,imageUrl:String
}
键入别名=
一串
类型别名SomeId=
一串
类型别名相关性=
一串
类型别名TraitWithRelevance=
(姓名、SomeId、相关性)
类型叛逆者添加
没有
|跟踪相关性
类型别名模型=
{contentWithTraits:contentWithTraits
,metaInfo:metaInfo
,traitToAdd:traitToAdd
,人:人
}
初始化:(模型,Cmd Msg)
初始化=
(模型contentWithTraits{name=“content name”,imageUrl=”http://weknowmemes.com/generator/uploads/generated/g1369409960206058073.jpg“}无{name=”“,gender=”“},Cmd.none)
contentWithTraits:contentWithTraits
满足于特性=
{someId=“某些默认id”
,特征=
[(“特征a”、“a”、“1”的名称)
(“这是特征b”、“b”、“50”的名称)
]
}
--更新
输入味精
=编辑特征SomeId相关性
|GetTraitResponse(结果Http.Error Person)
|重置
更新:Msg->Model->(Model,Cmd-Msg)
更新msg模型=
味精案例
EditTrait someId相关性->
让
_ =
Debug.log“model:”模型
在里面
(b)特征模型
让
_ =
Debug.log“response”resp
人=
案例响应
Ok val->
瓦尔
结果。错误e->
{name=”“,gender=”“}
在里面
({model | person=person},Cmd.none)
重置->
--(替换特征模型(列表跟踪相关->列表跟踪相关)->模型
替换特征模型函数=
{模型
|满足于特性=
{someId=model.contentWithTraits.someId
,traits=func model.contentWithTraits.traits
}
}
updateTrait:(SomeId,相关性)->TraitWithReleva