使用elm进行HTTP调用以修改数据

使用elm进行HTTP调用以修改数据,elm,Elm,如图所示,我创建了一个小示例程序,其中有一些控件可以修改模型的某些部分 我一直试图做的是发出一个HTTP请求以获取初始数据(它现在是硬编码的),或者稍后在收到重置消息时用来自所述HTTP请求的响应替换数据,但没有成功。我确实读过《榆树简介》,但我似乎无法把事情拼凑起来 我们的目标是拥有一个loadTraits函数,它接受一个字符串(SomeId)并返回一个TraitWithRelevance类型的列表,这样我就可以用传入的数据替换模型 module Main exposing (..) im

如图所示,我创建了一个小示例程序,其中有一些控件可以修改模型的某些部分

我一直试图做的是发出一个HTTP请求以获取初始数据(它现在是硬编码的),或者稍后在收到重置消息时用来自所述HTTP请求的响应替换数据,但没有成功。我确实读过《榆树简介》,但我似乎无法把事情拼凑起来

我们的目标是拥有一个loadTraits函数,它接受一个字符串(SomeId)并返回一个TraitWithRelevance类型的列表,这样我就可以用传入的数据替换模型

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