在输入事件侦听器上切换点击处理函数 — Javascript
Toggling A Click Handler Function On an Input Event Listener — Javascript
我正在设置一个表单,该表单通过 PHP 提交到 MySQL 数据库,并且出于安全原因进行了 server-side 验证。我希望使用 JavasScript 处理前端验证消息,因为站点上有许多类似的表单,并且希望将这些链接到 input
事件侦听器。
在下面的代码中,提交按钮有一个 preventDefault()
方法,直到标题超过 10 个字符。我读到添加和删除 preventDefault
的最佳方法是通过我正在使用的点击处理函数。
默认情况下,button
上有一个 .prevent-default
class,当输入通过验证时,它会被删除。
我遇到的问题
如果在输入的字符少于 10 个时提交表单,preventDefault
和错误消息会起作用,当然,如果输入的字符超过 10 个,表单将按预期提交。
但是,当最初输入超过 10 个字符,然后用户删除一些字符使计数回到 10 以下时,表单仍然在前端提交?我希望它再次失败,在单击提交按钮后显示相同的错误消息。
我认为解决方案是切换 checkValidations()
功能。不过我好像做不到。
注意: 一些元素使用 forEach
循环,因为在整个站点上将有多个表单实例。
CodePen Link: https://codepen.io/thechewy/pen/GROEmoN
var dmForm = document.querySelector("form"),
// class name on the submit button
preventSubmit = document.querySelectorAll(".prevent-submit"),
dmTitle = document.querySelector("#dm-title"),
// empty element for error message
dmTitleError = document.querySelector(".js-dm-title-error")
// function that prevents default click action on button and adds warning message
var clickHandler = function(evt) {
evt.preventDefault()
if(dmTitle.value.length < 10) {
dmTitleError.classList.add('warning')
dmTitleError.textContent = "Title must be more than 10 characters"
}
}
// checks for 'prevent-submit' class and if present invokes the clickHander function above
if (preventSubmit) {
preventSubmit.forEach(item => {
item.addEventListener('click', clickHandler, false)
})
// removes warning when the user types more than 10 characters
if (dmForm) {
dmTitle.addEventListener('input', () => {
if( dmTitle.value.length > 10) {
dmTitleError.classList.remove('warning')
dmTitleError.textContent = ""
// call the function that removes the preventDefault method
checkValidations()
}
})
}
function checkValidations(){
if (dmTitle.value.length > 10) {
preventSubmit.forEach(item => {
item.removeEventListener('click', clickHandler, false)
item.classList.remove('prevent-submit')
})
}
}
} // end of 'if (preventSubmit)' statement
body {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 0;
}
form {
display: flex;
align-items: center;
}
.input-wrapper {
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
input,
button {
padding: 0.5rem;
}
.js-error-message.warning {
background: #cc1f1f;
transition: background .5s;
padding: 0.2rem 0.5rem;
margin-top: 0.5rem;
display: inline-block;
position: absolute;
bottom: -5rem;
}
<form method="post">
<div class="input-wrapper">
<input id="dm-title" name="dm-title">
<p class="js-error-message js-dm-title-error"></p>
</div>
<button name="dm-submit" class="prevent-submit">SEND MESSAGE</button>
</form>
看起来你每次都需要删除验证,如果检测到错误,只需执行preventDefault
:
var dmForm = document.querySelector("form"),
// class name on the submit button
preventSubmit = document.querySelectorAll(".prevent-submit"),
dmTitle = document.querySelector("#dm-title"),
// empty element for error message
dmTitleError = document.querySelector(".js-dm-title-error")
// function that prevents default click action on button and adds warning message
var clickHandler = function(evt) {
if(dmTitle.value.length < 10) {
dmTitleError.classList.add('warning')
dmTitleError.textContent = "Title must be more than 10 characters"
evt.preventDefault(); // <-- prevent from sending and show warning
}
}
// checks for 'prevent-submit' class and if present invokes the clickHander function above
if (preventSubmit) {
preventSubmit.forEach(item => {
item.addEventListener('click', clickHandler, false)
})
// removes warning when the user types more than 10 characters
if (dmForm) {
dmTitle.addEventListener('input', () => {
if( dmTitle.value.length > 10) {
dmTitleError.classList.remove('warning')
dmTitleError.textContent = ""
}
})
}
} // end of 'if (preventSubmit)' statement
body {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 0;
}
form {
display: flex;
align-items: center;
}
.input-wrapper {
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
input,
button {
padding: 0.5rem;
}
.js-error-message.warning {
background: #cc1f1f;
transition: background .5s;
padding: 0.2rem 0.5rem;
margin-top: 0.5rem;
display: inline-block;
position: absolute;
bottom: -5rem;
}
<form method="post">
<div class="input-wrapper">
<input id="dm-title" name="dm-title">
<p class="js-error-message js-dm-title-error"></p>
</div>
<button name="dm-submit" class="prevent-submit">SEND MESSAGE</button>
</form>
如果使用内置的 DOM Constraint Validation API :
则更容易实现
let form = document.querySelector("form");
let error = document.querySelector(".js-dm-title-error")
let title = document.getElementById('dm-title');
title.setAttribute("minLength", '10');
title.addEventListener('input', function(e) {
if (!title.validity.valid) {
// if you want to nag on every character entered
//showError("Title must be more than 10 characters");
} else {
showError('');
}
});
form.addEventListener('submit', function(event) {
// check each field
if (!title.validity.valid) {
showError("Title must be more than 10 characters");
event.preventDefault();
return false;
}
// mimicking form submit
output.innerHTML += `Sending ${title.value}...<br>`;
event.preventDefault();
return false;
});
function showError(msg) {
if (msg) {
error.classList.add('warning')
error.textContent = msg;
} else {
error.classList.remove('warning');
}
}
body {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
padding: 0;
}
form {
display: flex;
align-items: center;
}
.input-wrapper {
position: relative;
}
input {
display: block;
margin-right: 0.5rem;
border-radius: 0.3rem;
}
input:invalid {
background-color: rgb(255, 220, 220);
}
input:invalid:required {
border: 1px dashed red;
}
input:valid {
background-color: rgb(211, 255, 211);
}
.js-error-message {
display: none;
position: absolute;
top: 100%;
}
.js-error-message.warning {
display: inline-block;
padding: .2rem;
width: 169px;
font-size: 80%;
color: white;
background-color: #900;
border-radius: 0 0 5px 5px;
box-sizing: border-box;
}
<form method="post" novalidate>
<div class="input-wrapper">
<input id="dm-title" name="dm-title" required>
<div class="js-error-message js-dm-title-error"></div>
</div>
<button name="dm-submit" class="prevent-submit">SEND MESSAGE</button>
</form><br>
<div id=output></div>
检查form.onsubmit事件会更合适。
https://codepen.io/_yigitt/pen/JjOpmPW
form1.onsubmit = function () {
if (inputFirstName.value.length < 10) {
p_error.classList.add("warning");
p_error.textContent = "Title must be more than 10 characters";
return false;
}
};
inputFirstName.oninput = function () {
if (this.value.length > 10) {
p_error.classList.remove("warning");
p_error.textContent = "";
}
};
所需的验证已内置 -- 不需要 JavaScript。当出现真正的错误时,闪烁错误消息是更好的用户体验。当您刚开始输入时,看到有关未满足要求的消息弹出,这让人很恼火。最好只在提交事件中显示错误消息。
下例中的输入有两个属性:
minlength="11"
提交时如果输入的字符少于或等于 10 个,表单将停止提交并弹出错误消息。
required
提交时如果input为空,表单将停止提交并弹出错误信息
此外,在这个简单的验证中没有奇怪的行为(例如输入 12 个字符,删除 5 个字符并成功提交)。同样在示例中,数据被发送到实时测试服务器并且 iframe 在那里显示服务器响应。
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<style>
*,
*::before,
*::after {
box-sizing: border-box;
}
:root {
font: 1ch/1.25 'Segoe UI';
}
html,
body {
width: 100%;
min-height: 100%;
margin: 0;
padding: 0;
}
body {
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
font-size: 2.5rem;
}
main {
width: 100%;
height: 100%;
margin: 0 auto;
}
input,
output,
button {
display: inline-block;
font-size: 100%;
}
input,
output {
font-family: Consolas;
line-height: 1.15;
}
button {
width: max-content;
padding: 2px 4px;
border-radius: 4px;
}
</style>
</head>
<body>
<main>
<form action='https://httpbin.org/post' method="post" target='response'>
<fieldset>
<legend>Direct Message</legend>
<input id="message" name="message" minlength='11' required>
<button name='btn'>Send Message</button>
</fieldset>
<fieldset>
<legend>Server Response</legend>
<iframe name='response'></iframe>
</fieldset>
</form>
</main>
<script></script>
</body>
</html>
我正在设置一个表单,该表单通过 PHP 提交到 MySQL 数据库,并且出于安全原因进行了 server-side 验证。我希望使用 JavasScript 处理前端验证消息,因为站点上有许多类似的表单,并且希望将这些链接到 input
事件侦听器。
在下面的代码中,提交按钮有一个 preventDefault()
方法,直到标题超过 10 个字符。我读到添加和删除 preventDefault
的最佳方法是通过我正在使用的点击处理函数。
默认情况下,button
上有一个 .prevent-default
class,当输入通过验证时,它会被删除。
我遇到的问题
如果在输入的字符少于 10 个时提交表单,preventDefault
和错误消息会起作用,当然,如果输入的字符超过 10 个,表单将按预期提交。
但是,当最初输入超过 10 个字符,然后用户删除一些字符使计数回到 10 以下时,表单仍然在前端提交?我希望它再次失败,在单击提交按钮后显示相同的错误消息。
我认为解决方案是切换 checkValidations()
功能。不过我好像做不到。
注意: 一些元素使用 forEach
循环,因为在整个站点上将有多个表单实例。
CodePen Link: https://codepen.io/thechewy/pen/GROEmoN
var dmForm = document.querySelector("form"),
// class name on the submit button
preventSubmit = document.querySelectorAll(".prevent-submit"),
dmTitle = document.querySelector("#dm-title"),
// empty element for error message
dmTitleError = document.querySelector(".js-dm-title-error")
// function that prevents default click action on button and adds warning message
var clickHandler = function(evt) {
evt.preventDefault()
if(dmTitle.value.length < 10) {
dmTitleError.classList.add('warning')
dmTitleError.textContent = "Title must be more than 10 characters"
}
}
// checks for 'prevent-submit' class and if present invokes the clickHander function above
if (preventSubmit) {
preventSubmit.forEach(item => {
item.addEventListener('click', clickHandler, false)
})
// removes warning when the user types more than 10 characters
if (dmForm) {
dmTitle.addEventListener('input', () => {
if( dmTitle.value.length > 10) {
dmTitleError.classList.remove('warning')
dmTitleError.textContent = ""
// call the function that removes the preventDefault method
checkValidations()
}
})
}
function checkValidations(){
if (dmTitle.value.length > 10) {
preventSubmit.forEach(item => {
item.removeEventListener('click', clickHandler, false)
item.classList.remove('prevent-submit')
})
}
}
} // end of 'if (preventSubmit)' statement
body {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 0;
}
form {
display: flex;
align-items: center;
}
.input-wrapper {
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
input,
button {
padding: 0.5rem;
}
.js-error-message.warning {
background: #cc1f1f;
transition: background .5s;
padding: 0.2rem 0.5rem;
margin-top: 0.5rem;
display: inline-block;
position: absolute;
bottom: -5rem;
}
<form method="post">
<div class="input-wrapper">
<input id="dm-title" name="dm-title">
<p class="js-error-message js-dm-title-error"></p>
</div>
<button name="dm-submit" class="prevent-submit">SEND MESSAGE</button>
</form>
看起来你每次都需要删除验证,如果检测到错误,只需执行preventDefault
:
var dmForm = document.querySelector("form"),
// class name on the submit button
preventSubmit = document.querySelectorAll(".prevent-submit"),
dmTitle = document.querySelector("#dm-title"),
// empty element for error message
dmTitleError = document.querySelector(".js-dm-title-error")
// function that prevents default click action on button and adds warning message
var clickHandler = function(evt) {
if(dmTitle.value.length < 10) {
dmTitleError.classList.add('warning')
dmTitleError.textContent = "Title must be more than 10 characters"
evt.preventDefault(); // <-- prevent from sending and show warning
}
}
// checks for 'prevent-submit' class and if present invokes the clickHander function above
if (preventSubmit) {
preventSubmit.forEach(item => {
item.addEventListener('click', clickHandler, false)
})
// removes warning when the user types more than 10 characters
if (dmForm) {
dmTitle.addEventListener('input', () => {
if( dmTitle.value.length > 10) {
dmTitleError.classList.remove('warning')
dmTitleError.textContent = ""
}
})
}
} // end of 'if (preventSubmit)' statement
body {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 0;
}
form {
display: flex;
align-items: center;
}
.input-wrapper {
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
input,
button {
padding: 0.5rem;
}
.js-error-message.warning {
background: #cc1f1f;
transition: background .5s;
padding: 0.2rem 0.5rem;
margin-top: 0.5rem;
display: inline-block;
position: absolute;
bottom: -5rem;
}
<form method="post">
<div class="input-wrapper">
<input id="dm-title" name="dm-title">
<p class="js-error-message js-dm-title-error"></p>
</div>
<button name="dm-submit" class="prevent-submit">SEND MESSAGE</button>
</form>
如果使用内置的 DOM Constraint Validation API :
则更容易实现let form = document.querySelector("form");
let error = document.querySelector(".js-dm-title-error")
let title = document.getElementById('dm-title');
title.setAttribute("minLength", '10');
title.addEventListener('input', function(e) {
if (!title.validity.valid) {
// if you want to nag on every character entered
//showError("Title must be more than 10 characters");
} else {
showError('');
}
});
form.addEventListener('submit', function(event) {
// check each field
if (!title.validity.valid) {
showError("Title must be more than 10 characters");
event.preventDefault();
return false;
}
// mimicking form submit
output.innerHTML += `Sending ${title.value}...<br>`;
event.preventDefault();
return false;
});
function showError(msg) {
if (msg) {
error.classList.add('warning')
error.textContent = msg;
} else {
error.classList.remove('warning');
}
}
body {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
padding: 0;
}
form {
display: flex;
align-items: center;
}
.input-wrapper {
position: relative;
}
input {
display: block;
margin-right: 0.5rem;
border-radius: 0.3rem;
}
input:invalid {
background-color: rgb(255, 220, 220);
}
input:invalid:required {
border: 1px dashed red;
}
input:valid {
background-color: rgb(211, 255, 211);
}
.js-error-message {
display: none;
position: absolute;
top: 100%;
}
.js-error-message.warning {
display: inline-block;
padding: .2rem;
width: 169px;
font-size: 80%;
color: white;
background-color: #900;
border-radius: 0 0 5px 5px;
box-sizing: border-box;
}
<form method="post" novalidate>
<div class="input-wrapper">
<input id="dm-title" name="dm-title" required>
<div class="js-error-message js-dm-title-error"></div>
</div>
<button name="dm-submit" class="prevent-submit">SEND MESSAGE</button>
</form><br>
<div id=output></div>
检查form.onsubmit事件会更合适。
https://codepen.io/_yigitt/pen/JjOpmPW
form1.onsubmit = function () {
if (inputFirstName.value.length < 10) {
p_error.classList.add("warning");
p_error.textContent = "Title must be more than 10 characters";
return false;
}
};
inputFirstName.oninput = function () {
if (this.value.length > 10) {
p_error.classList.remove("warning");
p_error.textContent = "";
}
};
所需的验证已内置 -- 不需要 JavaScript。当出现真正的错误时,闪烁错误消息是更好的用户体验。当您刚开始输入时,看到有关未满足要求的消息弹出,这让人很恼火。最好只在提交事件中显示错误消息。
下例中的输入有两个属性:
minlength="11"
提交时如果输入的字符少于或等于 10 个,表单将停止提交并弹出错误消息。required
提交时如果input为空,表单将停止提交并弹出错误信息
此外,在这个简单的验证中没有奇怪的行为(例如输入 12 个字符,删除 5 个字符并成功提交)。同样在示例中,数据被发送到实时测试服务器并且 iframe 在那里显示服务器响应。
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<style>
*,
*::before,
*::after {
box-sizing: border-box;
}
:root {
font: 1ch/1.25 'Segoe UI';
}
html,
body {
width: 100%;
min-height: 100%;
margin: 0;
padding: 0;
}
body {
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
font-size: 2.5rem;
}
main {
width: 100%;
height: 100%;
margin: 0 auto;
}
input,
output,
button {
display: inline-block;
font-size: 100%;
}
input,
output {
font-family: Consolas;
line-height: 1.15;
}
button {
width: max-content;
padding: 2px 4px;
border-radius: 4px;
}
</style>
</head>
<body>
<main>
<form action='https://httpbin.org/post' method="post" target='response'>
<fieldset>
<legend>Direct Message</legend>
<input id="message" name="message" minlength='11' required>
<button name='btn'>Send Message</button>
</fieldset>
<fieldset>
<legend>Server Response</legend>
<iframe name='response'></iframe>
</fieldset>
</form>
</main>
<script></script>
</body>
</html>