2017-02-22 68 views
5

我試圖製作一個內容可編輯標記,使用輸入來更新模型。Elm:Conditional preventDefault(with contentEditable)

我的代碼如下,這裏是一個版本,你可以在Ellie上玩。

on「blur」屬性在您點擊時工作並更新模型。但是我想在按下進入時獲得相同的「更新」功能。

view : Model -> Html Msg 
view model = 
    let 
     attrs = 
      [ contenteditable True 
       --, on "blur" (Json.map UpdateTitle targetTextContent) 
      , onInput2 UpdateTitle 
      , onEnter EnterPressed 
      , id "title" 
      , class "title" 
      ] 
    in 
     div [] 
      [ h1 attrs [ text model.existing ] 
      , text "Click above to start editing. Blur to save the value. The aim is to capture an <enter> and interpret that as a blur, i.e. to save the value and blur the field" 
      , p [] [ text <| "(" ++ model.existing ++ ")" ] 
      ] 


targetTextContent : Json.Decoder String 
targetTextContent = 
    Json.at [ "target", "textContent" ] Json.string 


onInput2 : (String -> msg) -> Attribute msg 
onInput2 msgCreator = 
    on "input" (Json.map msgCreator targetTextContent) 


onEnter : (Bool -> msg) -> Attribute msg 
onEnter enterMsg = 
    onWithOptions "keydown" 
     { stopPropagation = False 
     , preventDefault = False 
     } 
     (keyCode 
      |> Json.andThen 
       (\ch -> 
        let 
         _ = 
          Debug.log "on Enter" ch 
        in 
         Json.succeed (enterMsg <| ch == 13) 
       ) 
     ) 

此代碼似乎正在更新模型好,但DOM越來越亂了。例如,如果我進入「爆炸」後進入我看到這個

​​

我試圖切換到Html.Keyed和使用「的keydown」,但它並沒有任何區別,或只是創建了不同的問題。

+0

雖然我沒有回答您的問題,但我相信這與使用虛擬DOM有關。您可能想要調查React如何處理它。例如。 http://stackoverflow.com/q/30601516/1238847 – Tosh

回答

6

解決!關鍵點是使用Json.Decode.fail的過濾函數,以便只有<enter>受到preventDefault的約束。這個想法見https://github.com/elm-lang/virtual-dom/issues/18#issuecomment-273403774

view : Model -> Html Msg 
view model = 
    let 
     attrs = 
      [ contenteditable True 
      , on "blur" (Json.map UpdateTitle targetTextContent) 
      , onEnter EnterPressed 
      , id "title" 
      , class "title" 
      ] 
    in 
     div [] 
      [ h1 attrs [ text model.existing ] 
      , text "Click above to start editing. Blur to save the value. The aim is to capture an <enter> and interpret that as a blur, i.e. to save the value and blur the field" 
      , p [] [ text <| "(" ++ model.existing ++ ")" ] 
      ] 


targetTextContent : Json.Decoder String 
targetTextContent = 
    Json.at [ "target", "textContent" ] Json.string 


onEnter : msg -> Attribute msg 
onEnter msg = 
    let 
     options = 
      { defaultOptions | preventDefault = True } 

     filterKey code = 
      if code == 13 then 
       Json.succeed msg 
      else 
       Json.fail "ignored input" 

     decoder = 
      Html.Events.keyCode 
       |> Json.andThen filterKey 
    in 
     onWithOptions "keydown" options decoder