【问题标题】:Updating a record from a text input从文本输入更新记录
【发布时间】:2018-07-24 20:54:24
【问题描述】:

这里是相对的 Haskell 和反射菜鸟。决定用一个真实的应用程序来弄湿我的脚。

一旦用户在textInput 中输入文本,我在触发包含我的记录的动态更新时遇到问题。

代码在 GHCJS 中编译,但是一旦我打开网页,它就会显示为空白。 如果我删除标记为有问题的行(这会创建更新事件),它可以正常工作(即从 eClient 和清除按钮设置记录)。

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

编辑:我想我可能会在某处引入无限循环,所以尝试了几件事:

  • 不要将输入字段的setEventtextInput_input 事件连接到同一个Dynamic。这没有帮助
  • setValue 设置为eClient 而不是eUpdatedClient - 这是我们从外部接收的Event Client(例如,当单击表中的一行时)。没有帮助。
  • 再次从textInput_keypress 而不是textInput_input 触发Dynamic 更新以避免潜在的循环(尽管我认为这里不是这种情况。没有帮助。

不过,问题很可能是无限循环。

编辑:添加了另一个dynText,这表明事件eClientModified 触发了一个非常好的Client。所以它确实在更新editClient Dynamic 时失败了。

【问题讨论】:

    标签: haskell reflex reflex-dom


    【解决方案1】:

    tagDyn的文档中找到了我的问题的原因,最终:“另外,这意味着输出事件可能不能用于直接改变输入动态,因为这意味着它的值取决于它自己。当创建循环数据流,一般首选tag (current d) e。"

    不知何故,我希望这会神奇地起作用......

    因此,使用Behavior 代替Dynamic(和attachWith 代替attachPromptlyDynWith)进行更新事件可以正常工作。

    这是工作代码:

    updateFieldFromTextInput :: Reflex t =>
                                (Client -> T.Text -> Client) ->
                                Behavior t Client ->
                                Event t T.Text ->
                                Event t Client
    updateFieldFromTextInput setter bClient evInput = attachWith setter bClient 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 (current editClient) eNameInput
            eClear = mkClient "" <$ eClearButton
            eClientReplaced = leftmost [eClient, eClear]
            eClientModified = leftmost [eNameUpdate]
    
        -- the currently edited client
        editClient <- holdDyn (mkClient "") eClientModified
    
        -- 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多