relative Haskell and reflex noob here. Decided to get my feet wet with a real-world application.
I am having a problem with triggering an update to a Dynamic containing my record once the user enters text in a textInput
.
The code compiles in GHCJS, but once I open up the web page it shows up blank.
If I remove the line marked as problematic (which creates the update event) it works fine (i.e. setting the record from eClient
and from the clear button works).
data Client = Client
{ _clientName :: Text
, _contacts :: [Text] -- TODO make a new type for this
, _balance :: Int -- this is calculated
, _notes :: [Text] -- free text notes, might come in handy
} deriving (Show, Eq)
updateFieldFromTextInput :: Reflex t =>
(Client -> T.Text -> Client) ->
Dynamic t Client ->
Event t T.Text ->
Event t Client
updateFieldFromTextInput setter dynClient evInput = attachPromptlyDynWith setter dynClient evInput
-- the input event is the one to set a client on the widget
-- the output event is when a client is saved
clientEditWidget :: MonadWidget t m => Event t Client -> m (Event t Client)
clientEditWidget eClient = mdo
(editClient, eSaveButton) <- elClass "div" "client-edit" $ mdo
-- fires an Event t Client when the input field is changed
let eNameInput = (nameInput ^. textInput_input)
nameSetter = flip (clientName .~)
eNameUpdate = updateFieldFromTextInput nameSetter editClient eNameInput
eClear = mkClient "" <$ eClearButton
eClientReplaced = leftmost [eClient, eClear]
eClientModified = leftmost [eNameUpdate]
-- the currently edited client
-- using eClientModified causes a blank screen
-- editClient <- holdDyn (mkClient "") eClientModified
editClient <- holdDyn (mkClient "") eClientReplaced
-- lay out the widgets
text "edit client"
nameInput <- textInput $
def & setValue .~
((view clientName) <$> eClientReplaced)
contactsInput <- textArea $
def & setValue .~
((T.concat . view contacts) <$> eClientReplaced)
eSaveButton <- button "Save"
eClearButton <- button "Clear"
dynText =<< holdDyn "updated client will appear here" (T.pack . show <$> eClientModified)
return (editClient, eSaveButton)
return $ tagPromptlyDyn editClient eSaveButton
Edit: I thought I might be introducing an infinite loop somewhere, so tried a couple of things:
- don't hook up
setEvent
of the input field and thetextInput_input
event to the sameDynamic
. This did not help - set
setValue
toeClient
instead ofeUpdatedClient
- this is theEvent Client
that we are receiving from outside (e.g. when a row in a table is clicked). Did not help. - trigger the
Dynamic
update fromtextInput_keypress
instead oftextInput_input
again to avoid a potential loop (although I think this is not the case here. Did not help.
An infinite loop may well be the problem, though.
Edit: Added another dynText
which shows that the event eClientModified
fires a perfectly good Client
. So it is really in updating the editClient
Dynamic that it fails.