2015-12-21 91 views
1

在Elm中,您可以使用Json.decodeHttp package來請求json數據。我的嘗試是定期查找電子郵件(from this url)。定時器操作確實有效(我用簡單的計數器試了一下)。榆樹Json請求不起作用?

我已經使用this examplethis SO question作爲參考。

現在類型:

type alias Email = { title: String, ... } 

type Action = 
    NoAction 
    | TickCounter -- TODO rem 
    | AddEmails (List Email) 

然後,主+狀態+行動......

main: Signal Html 
main = Signal.map (view actions.address) state 

state: Signal Model 
state = Signal.foldp update makeEmptyModel input 

-- handle inputs (merging signals) 
input : Signal Action 
input = 
    Signal.mergeMany 
    [ actions.signal 
    -- , other actions 
    , Signal.map checkForNewMails (Time.every (Time.minute/6.0)) -- TODO precise timer (quick test) 
    ] 

actions: Signal.Mailbox Action 
actions = Signal.mailbox NoAction 

update: Action -> Model -> Model 
update action model = 
case action of 
    NoAction -> model 
    TickCounter -> { model | count = model.count + 1 } 
    AddEmails newMails -> { model | emails = newMails } 


checkForNewMails: Time -> Action 
checkForNewMails t = 
    let mails = startGettingEmailData 
    in TickCounter -- TODO replace with AddEmails using mails 

TickCounter是動作,這是我用來測試我的工作時序。但問題是startGettingEmailData。它使用下一個片段,但它不會觸發任何JSON請求(我通過控制檯檢查過它)。一旦解決,我可以將mails轉換爲一個動作,以便我可以在模型中添加電子郵件。

-- url to json 
jsonUrl = "https://dl.dropboxusercontent.com/u/14070433/temp.json" 

-- get emails 
startGettingEmailData: Task Http.Error (List Email) 
startGettingEmailData = Http.get emailJsonDecoder jsonUrl 

emailJsonDecoder: Json.Decoder (List Email) 
emailJsonDecoder = 
    let makeEmail = Json.object4 
      (\ti fr da bo -> makeNewEmail -1 ti fr da bo) 
      ("title" := Json.string) 
      ("from" := Json.string) 
      ("date" := Json.string) 
      ("body" := Json.string) 
    in 
     "emails" := Json.list makeEmail 

我的代碼有問題嗎?如果沒有,那麼是否有辦法檢查Http.Error內容? (也許問題不在於我的代碼,但在網絡中,但我可以通過瀏覽器訪問Dropbox文件...)

回答

2

您的代碼爲checkForNewMails實際上並沒有對mails做任何事情,所以它永遠不會被調用。 let語句不會進行任何調用,它只允許您在更大的函數體內定義一次性函數。由於in部分僅返回TickCounter,因此這意味着此函數僅返回TickCounter,並且不做其他任何操作。

此外,startGettingEmailData返回Task,這意味着它只在端口時被調用。您不能在僅返回Action的函數中使用它,因爲它永遠不會運行。

你不是想要寫一個port上的定時器觸發,然後創建一個Task其投票的網址,然後地圖,GET請求的行動迴應,稱actions郵箱。您可以使用Task.onError編寫一個簡單的錯誤處理程序,它可以通過在您的Action類型上創建一個Error String構造函數,將錯誤消息轉發給您的視圖。

下面是一個例子:

getEmailData _ = 
    let 
    request = 
     Http.get emailJsonDecoder jsonUrl 
     |> Task.map AddEmails 
    in 
    request 
     `Task.onError` (\err -> Task.succeed (Error (toString err))) 
     `Task.andThen` (\action -> Signal.send actions.address action) 

port getEmails : Signal (Task a()) 
port getEmails = 
    Signal.map getEmailData (Time.every (Time.minute/6.0)) 

上面的代碼將導致URL進行檢索,分析,然後,成功,就會引發你actions郵箱,並導致該視圖的更新。如果出現錯誤,它會發送一條消息給Error的新動作,您應該在視圖中處理該消息。 (您必須將Error String添加到Action聯合類型中,並在模型,更新和視圖函數中處理它)。

+0

我該如何觸發一個端口?你能給個例子嗎 ? – KarelG

+0

@KarelG:我用示例代碼更新了我的答案 –

+0

謝謝!看起來你可以將信號綁定到可以在其上運行的端口,只有在有數據時才發送信號。儘管我有一個誤解,但我認爲如果我閱讀[this],我必須包含JavaScript(http://elm-lang.org/guide/interop#ports)。 – KarelG