在一组复选框中使用HTML5的"required"属性?

236

当使用支持HTML5的新型浏览器(例如FireFox 4)时;

如果一个表单字段具有属性required='required'

并且该表单字段为空/空白;

并且单击提交按钮;

浏览器检测到“必填”字段为空,不会提交表单;

相反,浏览器会显示提示,要求用户在该字段中输入文本。

现在,我有一组复选框,其中至少应该由用户选中一个。

我如何在这组复选框上使用HTML5的required属性?

(因为只需要选中其中一个复选框,所以不能在每个复选框上都放置required属性)

附注:如果有影响,我正在使用simple_form


更新:

HTML5 multiple属性是否有用?有人用过类似于我的问题吗?HTML 5 multiple 属性

更新

看起来HTML5规范不支持这个功能:ISSUE-111: What does input.@required mean for @type = checkbox?

(问题状态:已标记为未作出裁决的关闭

并且这里是解释

更新2

这是一个老问题,但是想要澄清的是,最初提出这个问题的意图是在不使用JavaScript的情况下实现上述功能,也就是使用HTML5的方法来实现。回顾过去,我应该把“不使用JavaScript”表述得更明显。


5
这是一个很好的问题,适用于任何形式的输入,其中包括至少一个具有值或选中状态(但不是特定的值)的数组(包括文本输入)。演示 我认为可能没有一种方法可以实现这一点,但我希望有。 (顺便说一下,语言、框架或库无关,严格遵循HTML5) - Wesley Murch
感谢添加那个JSFiddle演示。希望有一些HTML5的方法来完成这个,否则可能需要使用JQuery和一个隐藏字段或其他东西来解决。 - Zabba
6
@natedavisolds,我认为在某些用户界面中使用多选框是有用的- 在我看来,选择多个复选框对终端用户更直观,特别是当复选框数量较少时- 而不是像多选框一样需要进行单击+选择。 - Zabba
@natedavisolds,你说得对。我会看一下@Wesley Murch提到的插件。问题仍然未解决! :) - Zabba
1
顺带提一下,您不需要整个required='required'的部分;只需输入'required'即可。 - William
显示剩余4条评论
18个回答

122

不幸的是,HTML5并没有提供一种开箱即用的方法来实现这一点。

不过,使用jQuery,您可以轻松地控制复选框组是否至少有一个已选元素。

请考虑以下DOM片段:

<div class="checkbox-group required">
    <input type="checkbox" name="checkbox_name[]">
    <input type="checkbox" name="checkbox_name[]">
    <input type="checkbox" name="checkbox_name[]">
    <input type="checkbox" name="checkbox_name[]">
</div>

您可以使用此表达式:
$('div.checkbox-group.required :checkbox:checked').length > 0

如果至少有一个元素被选中,则返回true。基于此,您可以实现验证检查。


@Clijsters 这个问题是关于使用HTML5的方式来解决它,而不是使用Javascript(当然,使用Javascript有各种可能的解决方案)。 - Zabba
11
@Zabba的回答是如何在HTML5中编写实现该功能,但遗憾的是HTML5并未提供开箱即用的方法来实现此功能。 - Clijsters
1
好的,@Clijsters - Zabba
以下是使用 setCustomValidity 的最佳实现方式 https://dev59.com/im025IYBdhLWcg3wGB0n#30222924/ - Alex78191

25

HTML5不直接支持要求在复选框组中仅选择一个/至少选择一个复选框。以下是我使用JavaScript的解决方案:

HTML


<input class='acb' type='checkbox' name='acheckbox[]' value='1' onclick='deRequire("acb")' required> One
<input class='acb' type='checkbox' name='acheckbox[]' value='2' onclick='deRequire("acb")' required> Two

JavaScript

function deRequireCb(elClass) {
  el = document.getElementsByClassName(elClass);

  var atLeastOneChecked = false; //at least one cb is checked
  for (i = 0; i < el.length; i++) {
    if (el[i].checked === true) {
      atLeastOneChecked = true;
    }
  }

  if (atLeastOneChecked === true) {
    for (i = 0; i < el.length; i++) {
      el[i].required = false;
    }
  } else {
    for (i = 0; i < el.length; i++) {
      el[i].required = true;
    }
  }
}

JavaScript 将确保至少一个复选框被选中,然后将整个复选框组设置为不必填。如果被选中的那个复选框变为未选中,则会再次要求填写所有复选框!


我喜欢这个解决方案,因为它可以更容易地用于验证同一表单上的不同复选框组。 - chillywilly
这个代码怎么算是干净的呢?它在窗口中污染了变量,比如 iel,没有在运算符周围使用适当的空格,使用过时的习语,并且在条件语句中有令人分心的冗余,比如 === true - ggorlen
你的函数名有拼写错误,请纠正。在HTML中应该是deRequire,在Javascript中应该是deRequireCb。 - Sushank Dahiwadkar
我喜欢这种方法,但做了一些改变。由于组内的所有复选框具有相同的名称,所以我使用名称而不是添加类。我还将deRequire重写如下: function deRequire(name){ let elements = document.getElementsByName(name); var someChecked = false; elements.forEach(element => someChecked = someChecked || element.checked); elements.forEach(element => element.required = !someChecked); } - skymatt70

24

这是一个简单的技巧。以下是您的HTML代码(请确保在组中为所有元素添加required属性)。此jQuery代码可以利用HTML5验证,通过更改required属性来检查是否已选中任何选项。

<input type="checkbox" name="option[]" id="option-1" value="option1" required/> Option 1
<input type="checkbox" name="option[]" id="option-2" value="option2" required/> Option 2
<input type="checkbox" name="option[]" id="option-3" value="option3" required/> Option 3
<input type="checkbox" name="option[]" id="option-4" value="option4" required/> Option 4
<input type="checkbox" name="option[]" id="option-5" value="option5" required/> Option 5

以下是jQuery脚本,如果任何一个选项被选中,则禁用进一步的验证检查。使用名称元素进行选择。

$cbx_group = $("input:checkbox[name='option[]']");
$cbx_group = $("input:checkbox[id^='option-']"); // name is not always helpful ;)

$cbx_group.prop('required', true);
if($cbx_group.is(":checked")){
  $cbx_group.prop('required', false);
}

需要注意的是:由于您正在使用HTML5验证,请确保在验证之前即在表单提交之前执行此操作。

// but this might not work as expected
$('form').submit(function(){
  // code goes here
});

// So, better USE THIS INSTEAD:
$('button[type="submit"]').on('click', function() {
  // skipping validation part mentioned above
});

虽然可以通过Javascript实现,但我在寻找不使用Javascript的解决方案。 - Zabba
3
到目前为止,我认为这是最好的答案。是的,它使用了JavaScript,但它使用HTML5的验证而不是弹出JavaScript警报。其他答案使用JS和JS弹出窗口。 - Cruz Nunez
1
这非常好。确保在那前两个jQuery行中选择其中一个(第二个会取消第一个)。还要确保将“option”更改为选项的名称。 - Allen Gingrich
鉴于 HTML5 并不支持原生实现此功能,这确实应该成为被接受的答案!我不想为站点上单个表单的一组复选框字段编写自己的验证库。 - JamesWilson

12

我猜HTML5没有标准的方法来做到这一点,但如果您不介意使用jQuery库,我已经能够使用webshims的“group-required”验证功能实现“复选框组”验证:

group-required的文档说:

如果一个复选框具有'class = group-required',则必须检查具有相同名称的表单/文档内的至少一个复选框。

以下是如何使用的示例:

<input name="checkbox-group" type="checkbox" class="group-required" id="checkbox-group-id" />
<input name="checkbox-group" type="checkbox" />
<input name="checkbox-group" type="checkbox" />
<input name="checkbox-group" type="checkbox" />
<input name="checkbox-group" type="checkbox" />

我主要使用webshims来填充HTML5功能,但它还有一些很棒的可选扩展功能,比如这个。

它甚至允许你编写自己的自定义有效性规则。例如,我需要创建一个不基于输入名称的复选框组,所以我编写了我的自定义有效性规则...


6

受到@thegauraw和@Brian Woodward的回答的启发,这里为JQuery用户整理了一些内容,包括自定义验证错误消息:

$cbx_group = $("input:checkbox[name^='group']");
$cbx_group.on("click", function () {
  if ($cbx_group.is(":checked")) {
    // checkboxes become unrequired as long as one is checked
    $cbx_group.prop("required", false).each(function () {
      this.setCustomValidity("");
    });
  } else {
    // require checkboxes and set custom validation error message
    $cbx_group.prop("required", true).each(function () {
      this.setCustomValidity("Please select at least one checkbox.");
    });
  }
});

请注意,我的表单默认选中了一些复选框。
也许你们中的一些JavaScript/JQuery高手可以进一步优化呢?

6
我们可以轻松地通过HTML5实现此功能,只需要添加一些jQuery代码即可。 演示 HTML
<form>
 <div class="form-group options">
   <input type="checkbox" name="type[]" value="A" required /> A
   <input type="checkbox" name="type[]" value="B" required /> B
   <input type="checkbox" name="type[]" value="C" required /> C
   <input type="submit">
 </div>
</form>

Jquery

$(function(){
    var requiredCheckboxes = $('.options :checkbox[required]');
    requiredCheckboxes.change(function(){
        if(requiredCheckboxes.is(':checked')) {
            requiredCheckboxes.removeAttr('required');
        } else {
            requiredCheckboxes.attr('required', 'required');
        }
    });
});

5

我在一组复选框中添加了一个不可见的单选框。

当至少有一个选项被勾选时,单选框也会被勾选。

当所有选项都被取消选择时,单选框也会被取消选择。

因此,表单使用单选框提示“请至少选择一个选项”

  • 你不能使用display: none,因为单选框无法聚焦。
  • 我使单选框的大小等于整个复选框的大小,这样提示更加明显。

HTML

<form>
  <div class="checkboxs-wrapper">
    <input id="radio-for-checkboxes" type="radio" name="radio-for-required-checkboxes" required/>
    <input type="checkbox" name="option[]" value="option1"/>
    <input type="checkbox" name="option[]" value="option2"/>
    <input type="checkbox" name="option[]" value="option3"/>
  </div>
  <input type="submit" value="submit"/>
</form>

Javascript

var inputs = document.querySelectorAll('[name="option[]"]')
var radioForCheckboxes = document.getElementById('radio-for-checkboxes')
function checkCheckboxes () {
    var isAtLeastOneServiceSelected = false;
    for(var i = inputs.length-1; i >= 0; --i) {
        if (inputs[i].checked) isAtLeastOneCheckboxSelected = true;
    }
    radioForCheckboxes.checked = isAtLeastOneCheckboxSelected
}
for(var i = inputs.length-1; i >= 0; --i) {
    inputs[i].addEventListener('change', checkCheckboxes)
}

CSS

.checkboxs-wrapper {
  position: relative;
}
.checkboxs-wrapper input[name="radio-for-required-checkboxes"] {
    position: absolute;
    margin: 0;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    -webkit-appearance: none;
    pointer-events: none;
    border: none;
    background: none;
}

https://jsfiddle.net/codus/q6ngpjyc/9/


这是一个很好的解决方案,运行得非常顺畅。然而,在Firefox中,当所有表单控件都使用此单选按钮且将其设置为必需时,单选按钮框周围会出现大红色轮廓。有没有一种方法可以在无效时(即未勾选所需的单选按钮时)将轮廓样式设置为不是红色,除非用户点击提交并进行验证? - gib65
我们可以将 radioopacity 设置为 0,并在提交时将 opacity 设置为 1,这样我们就可以控制红色轮廓是否出现。 - Codus
这个解决方案太聪明了!但在我的情况下,如果我使用 visibility: hiddendisplay: none 中的任何一个来避免让可用性有点混乱,它都不起作用。因为屏幕阅读器和其他辅助工具可能会找到隐藏的单选按钮。 - hoorider
为什么不直接使用JavaScript来实现,毕竟它是专门用于此目的的,而不是使用隐藏的HTML元素,这并不是它们的本意。 - reformed
是的,input type="radio" 不太好用(即使在 Firefox 98.0.1 中也是如此),但将其更改为 input type="text" 就非常好用了。当其中一个框未被选中时(假设您没有实现自定义验证消息),您最终会收到“请填写此字段”的消息,而不是“请选择其中一个选项”。但至少在我的情况下,前者的消息对于复选框组仍然很有意义,因为复选框包含在具有边框的字段中,就像您可能在纸质表格上看到的那样。 - user966939

3
我有同样的问题,我的解决方案是这样的:
HTML:
<form id="processForm.php" action="post">
  <div class="input check_boxes required wish_payment_type">
    <div class="wish_payment_type">
    <span class="checkbox payment-radio">
      <label for="wish_payment_type_1">
        <input class="check_boxes required" id="wish_payment_type_1" name="wish[payment_type][]" type="checkbox" value="1">Foo
      </label>
    </span>
    <span class="checkbox payment-radio">
      <label for="wish_payment_type_2">
        <input class="check_boxes required" id="wish_payment_type_2" name="wish[payment_type][]" type="checkbox" value="2">Bar
      </label>
    </span>
    <span class="checkbox payment-radio">
      <label for="wish_payment_type_3">
        <input class="check_boxes required" id="wish_payment_type_3" name="wish[payment_type][]" type="checkbox" value="3">Buzz
      </label>
          
      <input id='submit' type="submit" value="Submit">
  </div>
</form>

JS:
var verifyPaymentType = function () {
  var checkboxes = $('.wish_payment_type .checkbox');
  var inputs = checkboxes.find('input');
  var first = inputs.first()[0];

  inputs.on('change', function () {
    this.setCustomValidity('');
  });

  first.setCustomValidity(checkboxes.find('input:checked').length === 0 ? 'Choose one' : '');
}

$('#submit').click(verifyPaymentType);

https://jsfiddle.net/oywLo5z4/


inputs.on('change', function () { this.setCustomValidity(''); }); 是无用的 https://jsfiddle.net/d8r2146j/ - Alex78191
1
$('#submit').click(verifyPaymentType); 这是非常错误的,许多初学者都会犯这个错误,这对我来说意味着整个答案无效。请始终侦听表单提交事件。 - Edgar Griñant

2
您不需要使用jQuery来完成此操作。这里是一个使用事件监听器在复选框的父容器(checkbox-group-required)上,复选框元素的.checked属性和Array#some的原生JS概念证明。

const validate = el => {
  const checkboxes = el.querySelectorAll('input[type="checkbox"]');
  return [...checkboxes].some(e => e.checked);
};

const formEl = document.querySelector("form");
const statusEl = formEl.querySelector(".status-message");
const checkboxGroupEl = formEl.querySelector(".checkbox-group-required");

checkboxGroupEl.addEventListener("click", e => {
  statusEl.textContent = validate(checkboxGroupEl) ? "valid" : "invalid";
});

formEl.addEventListener("submit", e => {
  e.preventDefault();
  
  if (validate(checkboxGroupEl)) {
    statusEl.textContent = "Form submitted!";
    // Send data from e.target to your backend
  }
  else {
    statusEl.textContent = "Error: select at least one checkbox";
  }
});
<form>
  <div class="checkbox-group-required">
    <input type="checkbox">
    <input type="checkbox">
    <input type="checkbox">
    <input type="checkbox">
  </div>
  <input type="submit" />
  <div class="status-message"></div>
</form>

如果您需要验证多个组,请为每个组添加循环,可选择添加错误消息或CSS来指示哪个组未通过验证:

const validate = el => {
  const checkboxes = el.querySelectorAll('input[type="checkbox"]');
  return [...checkboxes].some(e => e.checked);
};
const allValid = els => [...els].every(validate);

const formEl = document.querySelector("form");
const statusEl = formEl.querySelector(".status-message");
const checkboxGroupEls = formEl.querySelectorAll(".checkbox-group-required");

checkboxGroupEls.forEach(el =>
  el.addEventListener("click", e => {
    statusEl.textContent = allValid(checkboxGroupEls) ? "valid" : "invalid";
  })
);

formEl.addEventListener("submit", e => {
  e.preventDefault();
  
  if (allValid(checkboxGroupEls)) {
    statusEl.textContent = "Form submitted!";
  }
  else {
    statusEl.textContent = "Error: select at least one checkbox from each group";
  }
});
<form>
  <div class="checkbox-group-required">
    <label>
      Group 1:
      <input type="checkbox">
      <input type="checkbox">
      <input type="checkbox">
      <input type="checkbox">
    </label>
  </div>
  <div class="checkbox-group-required">
    <label>
      Group 2:
      <input type="checkbox">
      <input type="checkbox">
      <input type="checkbox">
      <input type="checkbox">
    </label>
  </div>
  <input type="submit" />
  <div class="status-message"></div>
</form>


如果allValid(checkboxGroupEls)为真,如何继续提交?我在表单中有一个动作:action="includes/action.php" - Marlon Pereira
2
如果验证失败,可以通过AJAX请求或仅在必要时调用e.preventDefault()来阻止表单提交。 - ggorlen

2
我意识到这里有很多解决方案,但我发现没有一个符合我所有的要求:
  • 无需自定义编码
  • 代码在页面加载时运行
  • 不需要自定义类(复选框或其父级)
  • 我需要许多复选框列表共享相同的名称以通过Github API提交问题,并使用名称“label []”来分配跨越多个表单字段的标签(两个复选框列表和几个选择和文本框)- 可以实现不使用它们共享相同的名称,但是我决定尝试一下,而且奏效了。
此解决方案唯一的要求是jQuery,如果您想在vanilla JS中重写它,则可以轻松地消除它。 您可以结合@ewall的优秀解决方案添加自定义验证错误消息。

/* required checkboxes */
  jQuery(function ($) {
    var $requiredCheckboxes = $("input[type='checkbox'][required]");

    /* init all checkbox lists */
    $requiredCheckboxes.each(function (i, el) {
      //this could easily be changed to suit different parent containers
      var $checkboxList = $(this).closest("div, span, p, ul, td");

      if (!$checkboxList.hasClass("requiredCheckboxList"))
        $checkboxList.addClass("requiredCheckboxList");
    });

    var $requiredCheckboxLists = $(".requiredCheckboxList");

    $requiredCheckboxLists.each(function (i, el) {
      var $checkboxList = $(this);
      $checkboxList.on("change", "input[type='checkbox']", function (e) {
        updateCheckboxesRequired($(this).parents(".requiredCheckboxList"));
      });

      updateCheckboxesRequired($checkboxList);
    });

    function updateCheckboxesRequired($checkboxList) {
      var $chk = $checkboxList.find("input[type='checkbox']").eq(0),
        cblName = $chk.attr("name"),
        cblNameAttr = "[name='" + cblName + "']",
        $checkboxes = $checkboxList.find("input[type='checkbox']" + cblNameAttr);

      if ($checkboxList.find(cblNameAttr + ":checked").length > 0) {
        $checkboxes.prop("required", false);
      } else {
        $checkboxes.prop("required", true);
      }
    }

  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<form method="post" action="post.php">
    <div>
        Type of report:
    </div>
    <div>
        <input type="checkbox" id="chkTypeOfReportError" name="label[]" value="Error" required>
        <label for="chkTypeOfReportError">Error</label>

        <input type="checkbox" id="chkTypeOfReportQuestion" name="label[]" value="Question" required>
        <label for="chkTypeOfReportQuestion">Question</label>

        <input type="checkbox" id="chkTypeOfReportFeatureRequest" name="label[]" value="Feature Request" required>
        <label for="chkTypeOfReportFeatureRequest">Feature Request</label>
    </div>

    <div>
        Priority
    </div>
    <div>
        <input type="checkbox" id="chkTypeOfContributionBlog" name="label[]" value="Priority: High" required>
        <label for="chkPriorityHigh">High</label>


        <input type="checkbox" id="chkTypeOfContributionBlog" name="label[]" value="Priority: Medium" required>
        <label for="chkPriorityMedium">Medium</label>


        <input type="checkbox" id="chkTypeOfContributionLow" name="label[]" value="Priority: Low" required>
        <label for="chkPriorityMedium">Low</label>
    </div>
    <div>
        <input type="submit" />
    </div>
</form>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接