我有一个简单的HTML表单,最初是一系列问题(A1到A5和B1到B3),带有是/否的单选按钮:
<tr>
<td width="88%" valign="top" class="field_name_left">A1</td>
<td width="12%" valign="top" class="field_data">
<input type="radio" name="CriteriaA1" value="Yes">Yes<input type="radio" name="CriteriaA1" value="No">No</td>
</tr>
用户只能回答A系列问题或B系列问题,但不能回答两者。他们还必须完成A或B系列中的所有问题。
我现在还有一系列问题 - C1到C6 - 需要扩展我的验证脚本以确保用户输入A,B或C并回答每个系列中的所有问题。
我对A和B的原始脚本如下所示:
$(function() {
$("#editRecord").submit(function(){
// is anything checked?
if(!checkEmpty()){
$("#error").html("Please check something before submitting");
//alert("nothing Checked");
return false;
}
// Only A _OR_ B
if(isAorB()){
$("#error").html("Please complete A or B, not both");
//alert("please complete A or B, not both");
return false;
};
// all A's or all B's
if(allAorBChecked()){
$("#error").html("It appears you have not completed all questions");
//alert("missing data");
return false;
};
if(haveNo()){
// we're going on, but sending "type = C"
}
//alert("all OK");
return true;
});
});
function checkEmpty(){
var OK = false;
$(":radio").each(function(){
if (this.checked){
OK = true;
}
});
return OK;
}
function isAorB(){
var OK = false;
var Achecked = false;
var Bchecked = false;
$(":radio").each(function(){
var theChar=this.name.charAt(8);
// if we have an A checked remember it
if(theChar == "A" && this.checked && !Achecked){
Achecked = true;
}
if(Achecked && theChar == "B" && !Bchecked){
if(this.checked){
Bchecked = true;
}
}
if (Achecked && Bchecked){
OK = true;
}
});
return OK;
}
function allAorBChecked(){
var notOK = false;
var Achecked = false;
$(":radio").each(function(){
// skip through to see if we're doing A's or B's
var theChar=this.name.charAt(8);
// check the A's
if(theChar == "A" && this.checked && !Achecked){
Achecked = true;
}
});
if(Achecked){
// set the input to A
$("#type").val("A");
// check _all_ a's are checked
var thisName;
var thisChecked = false;
$(":radio").each(function(){
var theChar=this.name.charAt(8);
var checked = this.checked;
if (theChar == "A"){
if (this.name == thisName && !thisChecked){
// Yes wasn't checked - is No?
if(!checked){
notOK = true;
}
}
thisChecked = checked;
thisName = this.name;
}
});
}else{
// set the input to B
$("#type").val("B");
// check _all_ b's are checked
var thisName;
var thisChecked = false;
$(":radio").each(function(){
var theChar=this.name.charAt(8);
var checked = this.checked;
if (theChar == "B"){
if (this.name == thisName && !thisChecked){
// A wasn't checked - is B?
if(!checked){
notOK = true;
}
}
thisChecked = checked;
thisName = this.name;
}
});
}
return notOK;
}
function haveNo(){
var thisName;
var notOK = false;
$(":radio").each(function(){
var checked = this.checked;
if (this.name == thisName){
//Is this checked
if(checked){
notOK = true;
$("#type").val("C");
}
}
thisName = this.name;
});
return notOK;
}
这很好用,但我完全坚持将它扩展到包括C系列。我现在必须检查用户是否没有回答任何A和B,A和C以及B和C问题。我尝试的一切都无法验证。这是我现在使用我的新脚本的地方:
$(function() {
$("#editRecord").submit(function(){
// is anything checked?
if(!checkEmpty()){
$("#error").html("Please check something before submitting");
//alert("nothing Checked");
return false;
}
// Only A or B or C
if(isAorBorC()){
$("#error").html("Please complete A or B or C, not both");
//alert("please complete A or B, not both");
return false;
};
// all A's or all B's or all C's
if(allAorBorCChecked()){
$("#error").html("It appears you have not completed all questions");
//alert("missing data");
return false;
};
if(haveNo()){
// we're going on, but sending "type = C"
}
//alert("all OK");
return true;
});
});
function checkEmpty(){
var OK = false;
$(":radio").each(function(){
if (this.checked){
OK = true;
}
});
return OK;
}
function isAorBorC(){
var OK = false;
var Achecked = false;
var Bchecked = false;
var Cchecked = false;
$(":radio").each(function(){
var theChar=this.name.charAt(8);
// if we have an A checked remember it
if(theChar == "A" && this.checked && !Achecked){
Achecked = true;
}
if(theChar == "B" && this.checked && !Achecked){
Bchecked = true;
}
if(theChar == "C" && this.checked && !Achecked){
Cchecked = true;
}
if(Achecked && theChar == "B" && !Bchecked){
if(this.checked){
Bchecked = true;
}
}
if(Achecked && theChar == "C" && !Cchecked){
if(this.checked){
Cchecked = true;
}
}
if(Bchecked && theChar == "C" && !Cchecked){
if(this.checked){
Cchecked = true;
}
}
if (Achecked && Bchecked){
OK = true;
}
if (Achecked && CBchecked){
OK = true;
}
if (Bchecked && Cchecked){
OK = true;
}
});
return OK;
}
function allAorBorCChecked(){
var notOK = false;
var Achecked = false;
$(":radio").each(function(){
// skip through to see if we're doing A's or B's
var theChar=this.name.charAt(8);
// check the A's
if(theChar == "A" && this.checked && !Achecked){
Achecked = true;
}
});
if(Achecked){
// set the input to A
$("#type").val("A");
// check _all_ a's are checked
var thisName;
var thisChecked = false;
$(":radio").each(function(){
var theChar=this.name.charAt(8);
var checked = this.checked;
if (theChar == "A"){
if (this.name == thisName && !thisChecked){
// Yes wasn't checked - is No?
if(!checked){
notOK = true;
}
}
thisChecked = checked;
thisName = this.name;
}
});
}elseif{
// set the input to B
$("#type").val("B");
// check _all_ b's are checked
var thisName;
var thisChecked = false;
$(":radio").each(function(){
var theChar=this.name.charAt(8);
var checked = this.checked;
if (theChar == "B"){
if (this.name == thisName && !thisChecked){
// A wasn't checked - is B?
if(!checked){
notOK = true;
}
}
thisChecked = checked;
thisName = this.name;
}
});
}
return notOK;
}
}else{
// set the input to C
$("#type").val("C");
// check _all_ c's are checked
var thisName;
var thisChecked = false;
$(":radio").each(function(){
var theChar=this.name.charAt(8);
var checked = this.checked;
if (theChar == "C"){
if (this.name == thisName && !thisChecked){
// A wasn't checked - is B?
if(!checked){
notOK = true;
}
}
thisChecked = checked;
thisName = this.name;
}
});
}
return notOK;
}
function haveNo(){
var thisName;
var notOK = false;
$(":radio").each(function(){
var checked = this.checked;
if (this.name == thisName){
//Is this checked
if(checked){
notOK = true;
$("#type").val("C");
}
}
thisName = this.name;
});
return notOK;
}
任何人都能看到我做错了什么?
答案 0 :(得分:2)
为了大大简化您的任务,我建议创建一个单个函数来回答,对于给定的组:a)是否检查了任何内容; b)是否所有东西都经过检查。类似的东西:
function isAnyAllChecked(group) {
var any = false;
var all = true;
$(":radio").each(function(){
var theChar=this.name.charAt(8);
if(theChar == group && this.checked){
any = true;
}
if(theChar == group && !this.checked){
all = false;
}
});
return { any:any, all:all };
}
现在你的其他功能可以简单地重写为:
function isAorBorC() {
return (isAnyAllChecked("A").any ? 1 : 0) +
(isAnyAllChecked("B").any ? 1 : 0) +
(isAnyAllChecked("C").any ? 1 : 0) !== 1;
}
function allAorBorCChecked() {
var group = isAnyAllChecked("A").any ? "A" :
isAnyAllChecked("B").any ? "B" :
isAnyAllChecked("C").any ? "C" :
undefined;
if ( group ) {
$("#type").val(group);
return !isAnyAllChecked(group).all;
}
else
return true;
}
注意:
您可以重复使用isAnyAllChecked
的返回值来提高效率;我没有在上面的代码中这样做,以保持方法接口不变。
您可以<{em> typecast boolean
int
(隐式或明确地)而不是any ? 1 : 0
,但恕我直言更清楚。
您也可以将您的解决方案推广到任意数量的组,使用数组和函数,如map
,filter
等,但是对于少数你不需要的团体。
答案 1 :(得分:2)
首先,我认为最好的可用性是通过使表单更容易出错来使表单更易于使用。如果您使用的是javascript&amp; jQuery,你也可以设置它,以便用户必须选择一个部分才能选择其中的任何项目。您可以轻松支持显示所有问题的要求,但是当计算机可以非常容易地阻止此操作时,允许用户执行不必要的工作(例如错误地填写多个部分)对用户是不利的。
如果你想看看它的样子,请发表评论,我会为你做点什么。
与此同时,按照您当前的设计,这里是a fiddle demonstrating one possible technique。它适用于任意数量的部分。
请查看完整列表的代码,但这里是执行繁重验证的脚本。
function validate(ev) {
var sectionsTouched = $('ol').has(':checked'),
inputs = {},
errorMessage = '';
if (sectionsTouched.length === 0) {
errorMessage = 'Please check something before submitting.';
} else if (sectionsTouched.length > 1) {
errorMessage = 'Please complete only one of sections ' + namesCommaDelimited(seriesNames(), 'or') + '.';
} else {
sectionsTouched.find('input').each(function(i, e) {
var me = $(e), name = me.attr('name');
inputs[name] = !!inputs[name] || me.is(':checked');
});
$.each(inputs, function(k, v) {
if (!v) {
errorMessage = 'Please complete all questions in your selected section.';
}
return v;
});
}
if (errorMessage !== '') {
$('#error').html(errorMessage);
ev.preventDefault();
return false;
}
return true;
}
基本逻辑:如果没有任何部分有选中的项目,则显示相应的消息。如果多个部分有一个选中的项目,则有太多部分有答案。如果只有一个部分有答案,则循环输入并收集那些检查相应控件名称的列表。如果存在任何没有检查的名称,则取消选中某个控制组,并显示相应的消息。
我不得不采取一些自由来构建一个足以满足要求的表格,以便进行适当的演示。这是它的样子:
我希望这有帮助!
P.S。为了完整起见,我想提一下几种风格的考虑因素:
$('#error').html()
,而是设置一个值,然后只执行一次html设置。charAt(8)
函数,这会让它变得脆弱 - 如果其他人(甚至你未来的自己)意外地破坏了控制名称会怎么样?突然,javascript会破坏,两者之间的联系并不明显。您可以对其进行编码,这样您甚至不需要知道哪个部分是哪个部分,只要您有一些可以指示每个部分的选择器。使用类名是可以的,因为javascript中的类名显然必须匹配html中的类名。答案 2 :(得分:0)
首先,我认为最好的方法是为每个部分提供1个表单,并自行提交。您只验证该表单是否得到了所有答案,就是这样,剩下的就被丢弃了。
<form id="formA">
<input ...
<button type="submit">Submit with A Answers</button>
</form>
<form id="formB">
<input ...
<button type="submit">Submit with B Answers</button>
</form>
等。
但是,如果有理由说明你为什么这样做,那么无论你有多少部分,a,b,c,d,e等等,这里都是如何使它成功的小提琴......
还有一件事:有几种方法可以解决这个问题。 建议的Javascript是:
$('form').submit(function( e ){
e.preventDefault();
var globalAnswers = 0;
var globalComplete = false;
$('.section').each(function() {
var $this = $(this), sectionHasAnswers = false, sectionComplete = true;
$this.find('input[type="radio"]').each(function() {
var inputName = $(this).attr('name');
if ($('input[name="' + inputName + '"]').is(':checked')) {
sectionHasAnswers = true;
} else {
sectionComplete = false;
}
});
if (sectionComplete && !globalComplete) {
globalAnswers++
globalComplete = true;
} else {
if (sectionHasAnswers) {globalAnswers++};
}
});
if (globalAnswers == 1 && globalComplete) {
// EVERYTHING OK! SUBMIT FORM!
} else {
// ERRORS use globalAnswers and globalComplete for exact problem
}
});