首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Purescript Halogen手动触发表单外部的输入验证

Purescript Halogen手动触发表单外部的输入验证
EN

Stack Overflow用户
提问于 2018-04-24 19:34:53
回答 1查看 600关注 0票数 2

我有用required属性标记的输入字段,但无法找到触发验证检查的方法(我不在表单内部工作,因此使用默认的submit按钮操作对我无效)。

快速搜索显示了核心html元素类型的许多有效性函数,但我不知道如何将这些函数应用于Halogen。

有什么方法可以触发DOM效果来检查页面上所有必需的输入并得到结果吗?

下面是一个示例组件,展示了我正在努力实现的目标

代码语言:javascript
复制
import Prelude

import Data.Maybe (Maybe(..))
import Halogen as H
import Halogen.HTML as HH
import Halogen.HTML.Events as HE
import Halogen.HTML.Properties as HP

data Message = Void

type State =
  { textValue :: String
  , verified :: Boolean
  }

data Query a = ContinueClicked a | InputEntered String a

inputHtml :: State -> H.ComponentHTML Query
inputHtml state =
  HH.div [ HP.class_ $ H.ClassName "input-div" ]
         [ HH.label_ [ HH.text "This is a required field" ]
         , HH.input [ HP.type_ HP.InputText
                    , HE.onValueInput $ HE.input InputEntered
                    , HP.value state.textValue
                    , HP.required true
                    ]
         , HH.button [ HE.onClick $ HE.input_ ContinueClicked ]
                     [ HH.text "Continue"]
         ]

verifiedHtml :: H.ComponentHTML Query
verifiedHtml =
  HH.div_ [ HH.h3_ [ HH.text "Verified!" ] ]

render :: State -> H.ComponentHTML Query
render state = if state.verified then verifiedHtml else inputHtml state

eval :: forall m. Query ~> H.ComponentDSL State Query Message m
eval = case _ of
  InputEntered v next -> do
    H.modify $ (_ { textValue = v })
    pure next
  ContinueClicked next -> do
    let inputValid = false -- somehow use the required prop to determine if valid
    when inputValid $ H.modify $ (_ { verified = true })
    pure next

initialState :: State
initialState =
  { textValue : ""
  , verified : false
  }

component :: forall m. H.Component HH.HTML Query Unit Message m
component =
  H.component
    { initialState: const initialState
    , render
    , eval
    , receiver: const Nothing
    }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-04-25 23:13:01

我不认为依赖HTML表单验证是检查Halogen应用程序中输入的最有效方法。但我会假设你有自己的理由,并给出一个答案。

首先,如果我们想处理DOM元素,我们需要一种方法来检索它们。以下是document.getElementById的纯文本版本

代码语言:javascript
复制
getElementById
    :: forall a eff
     . (Foreign -> F a)
    -> String
    -> Eff (dom :: DOM | eff) (Maybe a)
getElementById reader elementId =
    DOM.window
        >>= DOM.document
        <#> DOM.htmlDocumentToNonElementParentNode
        >>= DOM.getElementById (wrap elementId)
        <#> (_ >>= runReader reader)

runReader :: forall a b. (Foreign -> F b) -> a -> Maybe b
runReader r =
    hush <<< runExcept <<< r <<< toForeign

(暂时不要担心新的进口,最终有一个完整的模块)

这个getElementById函数使用一个read*函数(可能来自DOM.HTML.Types)来确定返回的元素的类型,并将元素id作为字符串。

为了使用这一点,我们需要向HH.input添加一个额外的属性

代码语言:javascript
复制
HH.input [ HP.type_ HP.InputText
         , HE.onValueInput $ HE.input InputEntered
         , HP.value state.textValue
         , HP.required true
         , HP.id_ "myInput"  <-- edit
         ]

旁白:带有Show实例的sum类型比任何地方的硬编码字符串ids都安全。我会把那个留给你。

凉爽的。现在,我们需要从您的ContinueClicked函数的eval分支调用它:

代码语言:javascript
复制
ContinueClicked next ->
    do maybeInput <- H.liftEff $
            getElementById DOM.readHTMLInputElement "myInput"
    ...

这给了我们一个可以玩的Maybe HTMLInputElementHTMLInputElement应该有一个类型为ValidityStatevalidity属性,该属性包含我们要查找的信息。

DOM.HTML.HTMLInputElement有一个validity函数,它允许我们访问该属性。然后,我们需要进行一些外部值操作来尝试获取我们想要的数据。为了简单起见,让我们尝试提取valid字段:

代码语言:javascript
复制
isValid :: DOM.ValidityState -> Maybe Boolean
isValid =
    runReader (readProp "valid" >=> readBoolean)

有了这个小助手,我们就可以完成ContinueClicked分支了:

代码语言:javascript
复制
ContinueClicked next ->
    do maybeInput <- H.liftEff $
            getElementById DOM.readHTMLInputElement "myInput"

       pure next <*
       case maybeInput of
            Just input ->
                do validityState <- H.liftEff $ DOM.validity input
                   when (fromMaybe false $ isValid validityState) $
                        H.modify (_ { verified = true })
            Nothing ->
                H.liftEff $ log "myInput not found"

然后把我们所有的一切..。

代码语言:javascript
复制
module Main where

import Prelude

import Control.Monad.Aff (Aff)
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Console (CONSOLE, log)
import Control.Monad.Except (runExcept)

import Data.Either (hush)
import Data.Foreign (Foreign, F, toForeign, readBoolean)
import Data.Foreign.Index (readProp)
import Data.Maybe (Maybe(..), fromMaybe)
import Data.Newtype (wrap)

import DOM (DOM)
import DOM.HTML (window) as DOM
import DOM.HTML.HTMLInputElement (validity) as DOM
import DOM.HTML.Types
    (ValidityState, htmlDocumentToNonElementParentNode, readHTMLInputElement) as DOM
import DOM.HTML.Window (document) as DOM
import DOM.Node.NonElementParentNode (getElementById) as DOM

import Halogen as H
import Halogen.Aff as HA
import Halogen.HTML as HH
import Halogen.HTML.Events as HE
import Halogen.HTML.Properties as HP
import Halogen.VDom.Driver (runUI)

main :: Eff (HA.HalogenEffects (console :: CONSOLE)) Unit
main = HA.runHalogenAff do
    body <- HA.awaitBody
    runUI component unit body

type Message
    = Void

type Input
    = Unit

type State
    = { textValue    :: String
      , verified     :: Boolean
      }

data Query a
    = ContinueClicked a
    | InputEntered String a

component
    :: forall eff
     . H.Component HH.HTML Query Unit Message (Aff (console :: CONSOLE, dom :: DOM | eff))
component =
    H.component
        { initialState: const initialState
        , render
        , eval
        , receiver: const Nothing
        }

initialState :: State
initialState =
  { textValue : ""
  , verified : false
  }

render :: State -> H.ComponentHTML Query
render state =
    if state.verified then verifiedHtml else inputHtml
  where
    verifiedHtml =
        HH.div_ [ HH.h3_ [ HH.text "Verified!" ] ]

    inputHtml =
        HH.div
            [ HP.class_ $ H.ClassName "input-div" ]
            [ HH.label_ [ HH.text "This is a required field" ]
            , HH.input
                [ HP.type_ HP.InputText
                , HE.onValueInput $ HE.input InputEntered
                , HP.value state.textValue
                , HP.id_ "myInput"
                , HP.required true
                ]
            , HH.button
                [ HE.onClick $ HE.input_ ContinueClicked ]
                [ HH.text "Continue" ]
             ]

eval
    :: forall eff
     . Query
    ~> H.ComponentDSL State Query Message (Aff (console :: CONSOLE, dom :: DOM | eff))
eval = case _ of
    InputEntered v next ->
        do H.modify (_{ textValue = v })
           pure next

    ContinueClicked next ->
        do maybeInput <- H.liftEff $
                getElementById DOM.readHTMLInputElement "myInput"

           pure next <*
           case maybeInput of
                Just input ->
                    do validityState <- H.liftEff $ DOM.validity input
                       when (fromMaybe false $ isValid validityState) $
                            H.modify (_ { verified = true })
                Nothing ->
                    H.liftEff $ log "myInput not found"

getElementById
    :: forall a eff
     . (Foreign -> F a)
    -> String
    -> Eff (dom :: DOM | eff) (Maybe a)
getElementById reader elementId =
    DOM.window
        >>= DOM.document
        <#> DOM.htmlDocumentToNonElementParentNode
        >>= DOM.getElementById (wrap elementId)
        <#> (_ >>= runReader reader)

isValid :: DOM.ValidityState -> Maybe Boolean
isValid =
    runReader (readProp "valid" >=> readBoolean)

runReader :: forall a b. (Foreign -> F b) -> a -> Maybe b
runReader r =
    hush <<< runExcept <<< r <<< toForeign
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50009564

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档