【问题标题】:Is there a way to use prevent default and still receive post requests?有没有办法使用防止默认并仍然接收发布请求?
【发布时间】:2019-05-17 02:03:29
【问题描述】:

我正在尝试在我的后端正确验证表单数据,并且仍然能够在我的前端使用 Javascript 编写的表单验证获得良好的用户体验。我在前端完成了所有的表单验证,为了获得我们想要的效果,我们在提交按钮上使用了e.PreventDefault(),这样我们就可以在不重新加载的情况下向用户显示任何输入错误。问题是当您现在实际填写表单并单击提交时,由于 preventDefault,没有向服务器发送 POST 请求。

完全删除该行似乎解决了我们的服务器没有接收到 post 请求的问题,但这会导致前端表单验证完全没有意义的问题,因为由于刷新页面而没有显示错误消息。

Javascript 前端验证:

let btn = document.querySelector('.btn')

btn.addEventListener('click', function(e) {

    e.preventDefault() // <---- THIS IS THE ISSUE

    let firstName = document.querySelector('.firstName').value
    let lastName = document.querySelector('.lastName').value
    let email = document.querySelector('.email').value
    let createPassword = document.querySelector('.createPassword').value
    let verifyPassword = document.querySelector('.verifyPassword').value

    let firstNameSubmit = false
    let lasttNameSubmit = false
    let emailSubmit = false
    let createPasswordSubmit = false
    let verifyPasswordSubmit = false


    if (/^\s+$/.test(firstName) || firstName == null || firstName == '') {
        document.querySelector('.firstNameError').innerHTML = 'First Name is a required field'
        document.querySelector('.firstName').style.borderBottom = '1px solid red'

    } else if (!/^\s+$/.test(firstName) || firstName !== null || firstName !== '') {
        document.querySelector('.firstNameError').innerHTML = null
        document.querySelector('.firstName').style.borderBottom = '1px solid #2ecc71'
        firstNameSubmit = true

    } if (/^\s+$/.test(lastName) || lastName == null || lastName == '') {
        document.querySelector('.lastNameError').innerHTML = 'Last Name is a required field'
        document.querySelector('.lastName').style.borderBottom = '1px solid red'

    } else if (!/^\s+$/.test(lastName) || lastName !== null || lastName !== '') {
        document.querySelector('.lastNameError').innerHTML = null
        document.querySelector('.lastName').style.borderBottom = '1px solid #2ecc71'
        lasttNameSubmit = true

    } if (!/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email)) {
        document.querySelector('.emailError').innerHTML = 'Please enter a valid email'
        document.querySelector('.email').style.borderBottom = '1px solid red'

    } else if (/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email)) {
        document.querySelector('.emailError').innerHTML = null
        document.querySelector('.email').style.borderBottom = '1px solid #2ecc71'
        emailSubmit = true

    } if (/^\s+$/.test(createPassword) || createPassword == null || createPassword == '' || createPassword.length < 6) {
        document.querySelector('.createPasswordError').innerHTML = 'Password must be longer than 6 characters'
        document.querySelector('.createPassword').style.borderBottom = '1px solid red'

    } else if (!/^\s+$/.test(createPassword) || createPassword !== null || createPassword !== '' || createPassword.length >= 6) {
        document.querySelector('.createPasswordError').innerHTML = null
        document.querySelector('.createPassword').style.borderBottom = '1px solid #2ecc71'
        createPasswordSubmit = true

    } if (!createPasswordSubmit) {
        document.querySelector('.verifyPasswordError').innerHTML = `Passwords don't match`
        document.querySelector('.verifyPassword').style.borderBottom = '1px solid red'

    } else if (verifyPassword == createPassword){
        document.querySelector('.verifyPasswordError').innerHTML = null
        document.querySelector('.verifyPassword').style.borderBottom = '1px solid #2ecc71'
        verifyPasswordSubmit = true
    } 

Go 后端 Halders:

http.HandleFunc("/signup", signupHandler) // inside func main()


func signupHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method != "POST" {
        tpl.ExecuteTemplate(w, "signup.html", nil)
        fmt.Printf("METHOD: %s | URL: %v\n", r.Method, r.URL)
        return
    }
    fmt.Printf("METHOD: %s | URL: %v\n", r.Method, r.URL)

    r.ParseForm()
    f := r.PostFormValue("fname")
    l := r.PostFormValue("lname")
    e := r.PostFormValue("email")
    pw := r.PostFormValue("pass")

    hash, err := helper.HashPassword(pw) 
    if err != nil {
        fmt.Printf("Hashing Error")
    }

    fmt.Println("LoginValues")
    fmt.Printf("%s\n, %s\n, %s\n, %s\n", f, l, e, hash)
}

注册模板 HTML:

<form action="/signup" method="post">
     <h3>First Name</h3>
     <input name="fname" type="text" class="firstName">
     <p class="firstNameError"></p>
     <h3>Last Name</h3>
     <input name="lname" type="text" class="lastName">
     <p class="lastNameError"></p>
     <h3>Email</h3>
     <input name="email" type="text" class="email">
     <p class="emailError"></p>
     <h3>Create Password</h3>
     <input name="pass" type="password" class="createPassword">
     <p class="createPasswordError"></p>
     <h3>Verify Password</h3>
     <input type="password" class="verifyPassword">
     <p class="verifyPasswordError"></p>
     <button class="btn" type="submit">Register</button>
</form>

我只是想知道是否可以使用 preventDefault 来解决前端表单验证的问题,或者如果需要,我是否需要以不同的方式处理这个概念?提前致谢!

【问题讨论】:

  • 与其在检查错误之前调用preventDefault,不如在前端验证之后调用它,但只有在检测到错误时才调用它?

标签: javascript validation http-post preventdefault


【解决方案1】:

因为它是一个 type="submit" 按钮,所以 event.preventDefault() 正在阻止“提交”事件触发(而“提交”事件是将数据发送到后端)。

与其监听按钮上的“点击”事件,我认为最好监听表单上的“提交”事件。当您单击 type="submit" 的按钮时,它将在表单上触发。

表单现在将成为事件的目标。

let form = document.getElementById('my-form')
form.addEventListener('submit', function(event) {})

所以,在你的函数开始时,你应该能够通过调用来阻止提交操作

event.preventDefault();

但是,您也可以将表单存储到局部变量中,因为这是触发提交事件的元素:

let form = event.target

然后,如果没有错误,您可以在函数结束时触发表单上的提交:

form.submit()

大家一起:

let form = document.getElementById('my-form')
form.addEventListener('submit', function(event) {
   event.preventDefault()
   let form = event.target
   let errors = false;
   //do all of the error checking here, if there's an error, set errors to true
   if(!errors) {
       form.submit()
   }
})

(可能有更好的方法,但这就是我能想到的。另外,通过向每个输入添加“名称”属性可能更容易获取所有数据值,而不是查询每个字段)。

【讨论】:

    【解决方案2】:

    我通过弄乱@Maiya 提供的方法解决了这个问题。我退后一步,重新评估了 javascript 以及到底发生了什么。使用了一个提交甚至监听器,并在前端进行了基本的表单验证,现在我可以在后端确保。在我将表单实例存储在一个变量中然后检查并提交之后,我最终使用了e.preventDefault(),或者它只是显示错误。

    Javascript 更改:

    let submit = document.getElementById("signupForm")
    
    submit.addEventListener("submit", function(e){
        let form = e.target // get form instance
        e.preventDefault()
        console.log(form)
        // error handling
        if (firstNameSubmit == false || lasttNameSubmit  == false || emailSubmit == false || createPasswordSubmit == false || verifyPasswordSubmit == false) {
            console.log('form not done')
        } else { // form completed send to backend!
            form.submit()
        }
    

    SignupHandler 更改:

    user := &User{
            fname: r.PostFormValue("fname"),
            lname: r.PostFormValue("lname"),
            email: r.PostFormValue("email"),
            pw:    r.PostFormValue("pass"),
        }
        user.hash = string(helper.HashPassword(user.pw))
    
        //begin server validation
        if user.fname == "" {
            http.Redirect(w, r, "/signup", http.StatusBadRequest)
            tpl.ExecuteTemplate(w, "signup.html", nil)
        } else {
            http.Redirect(w, r, "/login", http.StatusOK)
        }
    

    【讨论】:

    • 作为一个细节,没有必要在将 e.target 分配给变量之后放置 e.preventDefault() 。 e.preventDefault() 只是阻止将触发的默认操作(提交请求和重新加载页面),但在调用 e.preventDefault() 后您仍然可以访问事件对象。
    猜你喜欢
    • 2016-10-28
    • 2020-10-10
    • 2013-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多