Halogen + contenteditable

Has anyone had any success using contenteditable on arbitrary elements in a nice way with Halogen? I think I got most of the way there, but I was forced into a bit of an FFI hack for the last part.

To make an HTML div that I can respond to input events on, I did this:

import DOM.HTML.Indexed (Interactive)
import Web.Event.Event (Event)
import Halogen.HTML (AttrName, ElemName(..), Node, element, text)
import Halogen.HTML.Properties (attr)

type HTMLeditDiv = Interactive (onScroll :: Event, onInput :: Event)

editDiv :: forall w i. Node HTMLeditDiv w i
editDiv = element (ElemName "div")

which I can then use as

editDiv [attr (AttrName "contenteditable") "true",
         onInput $ Just <<< HandleInput] [text "Some editable text"]

That works fine: the div is editable, and it generates the right events as you edit the text.

The problem comes when you come to process those events, because I need to extract the HTML text from the event target, and the only way I can see to do it is something like this:

foreign import editDivContent :: Event -> String

handleAction :: forall o m. MonadEffect m => Action -> HalogenM State Action () o m Unit
handleAction = case _ of
  HandleInput event -> do
    liftEffect $ log $ "EVENT: " <> editDivContent event

where editDivContent is this FFI function:

exports.editDivContent = function(event) {
  return event.target.innerHTML;

Is there a better way to do this? I fear I’ve just not read the docs for the event types properly!

1 Like