ReflexFRP: как установить текст кнопки из textInput при нажатии кнопки

У меня есть простой виджет, который должен установить «текст» кнопки из заданного поля ввода текста.

Пока мне удалось сделать простой понятный функционал

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

Мне не удалось установить метку кнопки - код ниже компилируется

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 ()

но, глядя на вывод index.html, я получаю только белую страницу с сообщением об ошибке консоли:

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


person epsilonhalbe    schedule 08.01.2017    source источник


Ответы (2)


Здесь происходит то, что button принимает строку (или текст, в зависимости от версии), и эта строка зависит от значения ввода текста, которое, в свою очередь, зависит от события, создаваемого кнопкой. Теперь, как правило, подобные циклы в сети событий просто прекрасны, но здесь вам нужно сэмплировать входное значение, чтобы получить текст прежде чем кнопка даже отобразится (потому что этот текст нужен для отображения в DOM).

Следующий код (написанный в hsnippet, поэтому старый reflex-dom и упрощенный (без объектива) показывает, как можно определить помощник «кнопку», которому не нужно реализовывать вводимый текст перед записью в 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
person Bartosz    schedule 08.01.2017

Кажется, что ванильные кнопки в reflex-dom не поддерживают динамическую маркировку; так что для

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 ()

нам нужно определить следующее:

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
person epsilonhalbe    schedule 08.01.2017
comment
О, вы узнали об этом раньше, чем я опубликовал свой ответ. Опубликовано в любом случае, с кратким объяснением того, что происходит. - person Bartosz; 09.01.2017
comment
Примечание: «кнопка» довольно странная с точки зрения API. Кажется, что это просто утилита для быстрого добавления некоторых кнопок, но она быстро становится бесполезной, как только вы хотите от нее большего. - person Bartosz; 09.01.2017