2015-12-18 14 views
5

Dire Ho un file JSON situato a http://www.randomurl.com/jobs.json, sembra che questo:leggere i dati da file JSON

{ "jobs": [ 
    { "task" : "turn burgers" , 
    "who" : "Anni" , 
    "place" : "Quick"} 
    , 
    { "task" : "dishes" , 
    "who" : "Bob" , 
    "place" : "McDo"} 
]} 

Ho fatto un decoder:

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) 

Come posso leggere in il file da quel sito Web usando il mio decoder? Presumo che ho bisogno del pacchetto Http ma non so come applicarlo.

risposta

9

Primo: la funzione decoder è leggermente disattivata. Non v'è alcun intermedio "attributi" oggetto, in modo da poter cambiare a questo:

decoder : Decoder Job 
decoder = 
    Decode.object3 Job 
    ("task" := Decode.string) 
    ("who" := Decode.string) 
    ("place" := Decode.string) 

Lei ha ragione che è necessario il pacchetto elm-http. Utilizzando questo, è possibile creare un'attività Http.get che associa il risultato a un'azione.

Come esempio di base, facciamo un pulsante che tira giù l'elenco dei lavori da un url. Avremo bisogno di un'azione GetJobs per attivare la richiesta HTTP e un'azione ShowJobs che verrà attivata quando la richiesta ritorna correttamente.

Supponendo che il nostro tipo di azione si presenta così:

type Action 
    = NoOp 
    | GetJobs 
    | ShowJobs (Maybe Jobs) 

Poi possiamo creare una funzione getJobs che costruisce un compito che può essere eseguito. Per questo semplice esempio, possiamo usare Task.toMaybe per sopprimere eventuali errori di decodifica HTTP o JSON.

getJobs : Effects Action 
getJobs = 
    Http.get decoderColl jobsUrl 
    |> Task.toMaybe 
    |> Task.map ShowJobs 
    |> Effects.task 

Al fine di incollare tutto insieme, useremo StartApp poiché ci consente di utilizzare le attività e gli effetti. Ecco un esempio funzionante che è possibile creare in locale, assumendo che jobs.json esista nella stessa directory.

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) 
+0

Per qualche motivo, quando provo a compilare il codice, la memoria è esaurita, non l'ho mai avuta prima. – Stanko

+0

Trovato il problema, avevo bisogno di cambiare '({model | jobs = Nothing}, getJobs)' a '({model | jobs <- Nothing}, getJobs)'. Qual è la differenza tra '=' e '<-'? – Stanko

+0

'<-' è stato modificato in' = 'in quel contesto recentemente nella versione 0.16. Sembra che tu abbia solo bisogno dell'ultima versione di elm –

Problemi correlati