3

I have a simple widget that should set the "text" of a button from a given text input field.

While I managed to do a simple clear functionality

buttonWidget :: MonadWidget t m => m ()
buttonWidget = do
  send  <- button "clear"
  input <- textInput $ def & setValue .~ fmap (const "") send
  return ()

I did not manage to set the button label - the code below compiles

buttonWidget :: MonadWidget t m => m ()
buttonWidget = do
  rec send  <- button val
      input <- textInput $ def & setValue .~ fmap (const "") send
      val   <- sample $ current $ view textInput_value input
  return ()

but looking at the output index.html - I get only a white page with a console error message:

rts.js:7313 thread blocked indefinitely in an MVar operation

epsilonhalbe
  • 15,637
  • 5
  • 46
  • 74

2 Answers2

3

It seems that vanilla buttons in reflex-dom do not support dynamic labeling; so for the

solutionWidget :: MonadWidget t m => m ()
solutionWidget = do
  rec send  <- dynButton dyn
      input <- textInput $ def & setValue .~ fmap (const "") send
      dyn <- holdDyn "click button to set text below"
                     (tag (current $ view textInput_value input) send)
  return ()

we need to define the following:

dynButton :: MonadWidget t m => Dynamic t Text -> m (Event t ())
dynButton s = do
  (e, _) <- elAttr' "button" (Map.singleton "type" "button") $ dynText s
  return $ domEvent Click e
epsilonhalbe
  • 15,637
  • 5
  • 46
  • 74
  • Oh, you've found it out earlier than I posted my answer. Posted anyway, with short explanation of what's going on. – Bartosz Jan 08 '17 at 23:12
  • Aside note: 'button' is kind of weird from the API point of view. It seems like it's just made to be an util to quickly add some buttons, but quickly becomes useless once you want more from it. – Bartosz Jan 08 '17 at 23:13
3

What happens here is that button takes String (or Text, depending on version), and this string depends on the value of text input, which, in turn, depends on the event produced by a button. Now, normally similar loops in event network are just fine, but here you need to sample the input value to obtain the text before the button is even rendered (because it needs that text to render to DOM).

Following code (written in hsnippet, so older reflex-dom, and simplified (no lens), shows how one can defined a 'button' helper that does not need to have the input text realized before being written to DOM:

app :: MonadWidget t m => App t m ()
app = do
  rec send  <- button' $ _textInput_value input
      input <- textInput $ def { _textInputConfig_setValue = fmap (const "") send }
  return ()

button' :: MonadWidget t m => Dynamic t String -> m (Event t ())
button' s = do
  (e, _) <- elAttr' "button" (M.singleton "type" "button") $ dynText s
  return $ domEvent Click e
Bartosz
  • 3,318
  • 21
  • 31