假设我有一个位于http://www.randomurl.com/jobs.json的JSON文件,它看起来像这样:
{ "jobs": [ { "task" : "turn burgers" , "who" : "Anni" , "place" : "Quick"} , { "task" : "dishes" , "who" : "Bob" , "place" : "McDo"} ]}
我做了一个解码器:
type alias Job = { task : String , who : String , place: String } type alias Jobs = List Job decoder : Decoder Job decoder = Decode.object3 Job (Decode.at ["attributes", "task"] Decode.string) (Decode.at ["attributes", "who"] Decode.string) (Decode.at ["attributes", "place"] Decode.string) decoderColl : Decoder Jobs decoderColl = Decode.object1 identity ("jobs" := Decode.list decoder)
如何使用我的解码器从该网站读取文件?我认为我需要Http包,但我不知道如何应用它.
首先关闭 - 你的decoder
功能略有偏差.没有中间的"属性"对象,因此您可以将其更改为:
decoder : Decoder Job
decoder =
Decode.object3 Job
("task" := Decode.string)
("who" := Decode.string)
("place" := Decode.string)
你是正确的,你需要elm-http包.使用此功能,您可以创建Http.get
将结果映射到操作的任务.
作为一个基本的例子,让我们创建一个按钮,从网址中下拉作业列表.我们需要一个GetJobs
动作来触发HTTP请求,以及一个ShowJobs
在请求成功返回时触发的动作.
假设我们的Action类型如下所示:
type Action
= NoOp
| GetJobs
| ShowJobs (Maybe Jobs)
然后我们可以创建一个getJobs
构建可以运行的任务的函数.对于这个简单的示例,我们可以使用Task.toMaybe
来抑制任何HTTP或JSON解码错误.
getJobs : Effects Action
getJobs =
Http.get decoderColl jobsUrl
|> Task.toMaybe
|> Task.map ShowJobs
|> Effects.task
为了将它们粘合在一起,我们将使用StartApp,因为它允许我们使用任务和效果.这是一个可以在本地构建的工作示例,假设jobs.json存在于同一目录中.
import Http
import StartApp
import Effects exposing (Effects,Never)
import Task
import Html exposing (..)
import Html.Events exposing (..)
import Json.Decode as Decode exposing (Decoder, (:=))
jobsUrl = "./jobs.json"
-- StartApp plumbing
app =
StartApp.start { init = init, view = view, update = update, inputs = [] }
main =
app.html
port tasks : Signal (Task.Task Never ())
port tasks =
app.tasks
type Action
= NoOp
| GetJobs
| ShowJobs (Maybe Jobs)
type alias Model =
{ jobs : Maybe Jobs }
init =
({ jobs = Nothing }, Effects.none)
update action model =
case action of
NoOp ->
(model, Effects.none)
GetJobs ->
({ model | jobs = Nothing }, getJobs)
ShowJobs maybeJobs ->
({ model | jobs = maybeJobs }, Effects.none)
view address model =
div []
[ button [ onClick address GetJobs ] [ text "Click to get jobs!" ]
, viewJobs model.jobs
]
viewJobs maybeJobs =
let
viewJob job =
li [] [ text ("Task: " ++ job.task ++ "; Who: " ++ job.who ++ "; Place: " ++ job.place) ]
in
case maybeJobs of
Nothing ->
div [] [ text "No jobs to display. Try clicking the button" ]
Just jobs ->
ul [] (List.map viewJob jobs)
-- This is the key to map the result of the HTTP GET to an Action
-- Note: Task.toMaybe swallows any HTTP or JSON decoding errors
getJobs : Effects Action
getJobs =
Http.get decoderColl jobsUrl
|> Task.toMaybe
|> Task.map ShowJobs
|> Effects.task
-- An alternative to Task.toMaybe which dumps error information to the console log
toMaybeWithLogging : Task.Task x a -> Task.Task y (Maybe a)
toMaybeWithLogging task =
Task.map Just task `Task.onError` (\msg -> Debug.log (toString msg) (Task.succeed Nothing))
-- The Job type aliases from the question
type alias Job = {
task : String
, who : String
, place: String
}
type alias Jobs = List Job
-- The updated Job decoder
decoder : Decoder Job
decoder =
Decode.object3 Job
("task" := Decode.string)
("who" := Decode.string)
("place" := Decode.string)
decoderColl : Decoder Jobs
decoderColl =
Decode.object1 identity
("jobs" := Decode.list decoder)