2015-12-18 6 views
5

sagen, dass ich eine JSON-Datei auf http://www.randomurl.com/jobs.json gelegen haben, sieht es so aus:Lesen von Daten aus JSON-Datei

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) 

Wie ich in lesen:

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

ich einen Decoder gemacht habe die Datei von dieser Website mit meinem Decoder? Ich nehme an, ich brauche das Http-Paket, aber ich weiß nicht, wie ich es anwenden soll.

Antwort

9

Zunächst einmal - Ihre decoder Funktion ist etwas aus. Es gibt keine Zwischen „Attribute“ Objekt, so können Sie es auf diese ändern:

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

Sie sind richtig, dass Sie die elm-http Paket benötigen. Damit können Sie eine Http.get Aufgabe erstellen, die das Ergebnis einer Aktion zuordnet.

Als ein grundlegendes Beispiel, machen wir eine Schaltfläche, die die Liste der Aufträge von einer URL herunterzieht. Wir benötigen eine GetJobs Aktion, um die HTTP-Anfrage auszulösen, und eine ShowJobs Aktion, die ausgelöst wird, wenn die Anfrage erfolgreich zurückkommt.

Art unsere Aktion Unter der Annahme, sieht wie folgt aus:

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

Dann können wir eine getJobs Funktion erstellen, die eine Aufgabe erstellt, die ausgeführt werden können. In diesem einfachen Beispiel können wir Task.toMaybe verwenden, um HTTP- oder JSON-Decodierungsfehler zu unterdrücken.

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

Um sie alle zusammen zu kleben, werden wir StartApp verwenden, da es uns Aufgaben und Effekte nutzen können. Hier ist ein Arbeitsbeispiel, das Sie lokal erstellen können, vorausgesetzt, dass jobs.json in demselben Verzeichnis vorhanden ist.

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

Aus irgendeinem Grund, wenn ich versuche, Ihren Code zu kompilieren, läuft es aus dem Speicher, hatte noch nie zuvor. – Stanko

+0

Das Problem gefunden, ich musste '({model | jobs = Nothing}, getJobs) '' '({model | jobs <- Nothing}, getJobs)' 'ändern. Was ist der Unterschied zwischen '=' und '<-'? – Stanko

+0

'<-' wurde kürzlich in Version 0.16 zu' = 'in diesem Zusammenhang geändert. Klingt wie du brauchst nur die neueste Version von Ulme –