2016-04-03 43 views
9

這是一個非常基本的問題,但我沒有找到任何示例。
我有這樣一個觀點:如何在Elm中提交表單?

view address model = 
    div [] 
    [ div [] [ text <|"ID : " ++ toString model.id ] 
    , form 
     [] 
     [ input [ value model.title ] [] 
     , textarea [ value model.content ] [] 
     , button [ onClick address (SubmitPost model) ] [ text "Submit" ] // Here is the issue, I want to send my updated model 
     ] 
    ] 

因此,它顯示與裏面的內容的形式。
因此,如果我在我的輸入和textarea中寫入更新內容,如何在按鈕上的「onClick」事件上「抓住」我更新的模型以發送它?

回答

20

在Elm中處理表單的標準方式是觸發對模型的更新,只要任何東西在表單上發生更改。您通常會看到某種類型的附加到每個表單元素的事件屬性on

對於您的示例,您需要使用on "input"來觸發使用最新值更新模型的事件。但在我們做到這一點之前,我們需要創建一些響應任一領域更新的操作。

type Action 
    = SubmitPost 
    | UpdateTitle String 
    | UpdateContent String 

我把改變你SubmitPost Model行動只是SubmitPost的自由。由於我們將您的代碼更改爲始終保持最新狀態,因此您無需執行任何操作,只需執行SubmitPost即可觸發提交的事件。

現在,你有額外的操作,你需要處理他們在update功能:

update action model = 
    case action of 
    UpdateTitle s -> 
     ({ model | title = s }, Effects.none) 
    UpdateContent s -> 
     ({ model | content = s }, Effects.none) 
    ... 

我們現在可以on屬性添加到您的文本字段觸發更新,每當有什麼變化。 "input"是瀏覽器在文本內容發生變化時會觸發的事件,它不僅讓您看到類似keypress事件的內容,還可以提供更多的報道。

view address model = 
    div [] 
    [ div [] [ text <| "ID : " ++ toString model.id ] 
    , form 
     [] 
     [ input 
     [ value model.title 
     , on "input" targetValue (Signal.message address << UpdateTitle) 
     ] 
     [] 
     , textarea 
     [ value model.content 
     , on "input" targetValue (Signal.message address << UpdateContent) 
     ] 
     [] 
     , button [ onClick address SubmitPost ] [ text "Submit" ] 
     ] 
    ] 

targetValue解碼器是一個JSON解碼器,其檢查在被解僱,向下鑽取的javascript對象,其中包含的文本字段的全部價值內的event.target.value字段的JavaScript事件。

+0

感謝您的幫助。我會放棄榆樹,等待真正的方法來做到這一點。 2016年,不得不破解榆樹提交表單只是愚蠢的。我將等待榆樹成熟 – BoumTAC

+13

@BoumTAC這不是「黑客」,這是你如何在榆樹代碼。 – halfzebra

+1

@halfzebra我明白,但我也明白我們在2016年不是2005年。我也明白人們永遠不會使用榆木,如果它是這樣的 – BoumTAC

4

Full example on ellie爲ELM-0.18,基於http://musigma.org/elm/2016/11/28/elm.html

保存以下文件作爲Main.elm

module Main exposing (main) 

import Html exposing (Html, div, text, form, textarea, button, input) 
import Html.Attributes exposing (type_, action, value, disabled) 
import Html.Events exposing (onSubmit, onInput) 
import Http 
import Json.Decode as Json 
import Json.Encode 


type alias Model = 
    { newComment : NewComment 
    , comments : List Comment 
    } 


emptyModel : Model 
emptyModel = 
    { newComment = emptyNewComment 
    , comments = [] 
    } 


emptyNewComment = 
    NewComment -1 "" "" 


type alias NewComment = 
    { userId : Int 
    , title : String 
    , body : String 
    } 


type Msg 
    = AddComment 
    | UpdateComment NewComment 
    | AddCommentHttp (Result Http.Error Comment) 


update : Msg -> Model -> (Model, Cmd Msg) 
update msg model = 
    case msg of 
     AddComment -> 
      let 
       newComment = 
        Debug.log "model.newComment" model.newComment 
      in 
       ({ model | newComment = emptyNewComment }, postComment newComment) 

     UpdateComment newComment -> 
      ({ model | newComment = newComment }, Cmd.none) 

     AddCommentHttp (Ok response) -> 
      let 
       _ = 
        Debug.log "response" response 
      in 
       ({ model | comments = model.comments ++ [ response ] }, Cmd.none) 

     AddCommentHttp (Err err) -> 
      let 
       _ = 
        Debug.log "err" err 
      in 
       (model, Cmd.none) 


postComment newComment = 
    Http.send AddCommentHttp 
     (Http.post "https://jsonplaceholder.typicode.com/posts" 
      (encodeNewComment newComment) 
      decodeComment 
     ) 


encodeNewComment : NewComment -> Http.Body 
encodeNewComment newComment = 
    Http.jsonBody <| 
     Json.Encode.object 
      [ ("title", Json.Encode.string newComment.title) 
      , ("body", Json.Encode.string newComment.body) 
      , ("userId", Json.Encode.int newComment.userId) 
      ] 


type alias Comment = 
    { title : String 
    , body : String 
    , userId : Int 
    , id : Int 
    } 


decodeComment : Json.Decoder Comment 
decodeComment = 
    Json.map4 Comment 
     (Json.field "title" Json.string) 
     (Json.field "body" Json.string) 
     (Json.field "userId" Json.int) 
     (Json.field "id" Json.int) 


view : Model -> Html Msg 
view model = 
    div [] <| 
     [ viewForm model.newComment UpdateComment AddComment 
     ] 
      ++ List.map (\comment -> div [] [ text <| toString comment ]) model.comments 


viewForm : NewComment -> (NewComment -> msg) -> msg -> Html msg 
viewForm newComment toUpdateComment addComment = 
    form 
     [ onSubmit addComment, action "javascript:void(0);" ] 
     [ div [] 
      [ input 
       [ value newComment.title 
       , onInput (\v -> toUpdateComment { newComment | title = v }) 
       ] 
       [] 
      ] 
     , textarea 
      [ value newComment.body 
      , onInput (\v -> toUpdateComment { newComment | body = v }) 
      ] 
      [] 
     , div [] 
      [ button 
       [ type_ "submit" 
       , disabled <| isEmpty newComment.title || isEmpty newComment.body 
       ] 
       [ text "Add Comment" ] 
      ] 
     ] 


isEmpty : String -> Bool 
isEmpty = 
    String.isEmpty << String.trim 


main : Program Never Model Msg 
main = 
    Html.program 
     { view = view 
     , update = update 
     , subscriptions = \_ -> Sub.none 
     , init = (emptyModel, Cmd.none) 
     } 

並運行:

elm package install -y elm-lang/http 
elm-reactor 

打開網頁瀏覽器http://localhost:8000/Main.elm

+0

非常好!但是我花了一些時間來弄清'onInput <|中的「標題」 (toUpdateComment << \title -> NewComment 1 title newComment.body)'將直接來自'onInput'。 – farmio

+1

我已將它更改爲'onInput(\ v - > toUpdateComment {newComment | title = v})''。應該更清楚 – rofrol

3

這是我發現的「最新」方式在Elm(0.18)中定義一個HTML表單如下。注意,它鉤入了表單標籤的onSubmit屬性,而不是一個特定按鈕的onClick。

view : Model -> Html Msg 
view model = 
    Html.form 
     [ class "my-form" 
     , onWithOptions 
      "submit" 
      { preventDefault = True, stopPropagation = False } 
      (Json.Decode.succeed SubmitPost) 
     ] 
     [ button [] 
      [ text "Submit" 
      ] 
     ] 
+1

當你收到一個'SubmitPost'方法時,你在'update'函數中做了什麼 –

+0

看起來像'action「javascript:void(0);」'不需要。 https://ellie-app.com/9zTH65GHXa1/0和'onSubmit'已經將'preventDefault'設置爲'True' https://github.com/elm-lang/html/blob/2.0.0/src/Html /Events.elm#L130 – rofrol