如何重构此 jquery 代码以计算选中的选项并相应地设置消息而无需重复相同的代码

how to refactor this jquery code to count checked options and set message accordingly without having to repeat same code

我有几组复选框,每组都有一个“none of the above”选项(输入值='none')。我有一个工作代码,每个组都重复该代码以计数并相应地设置消息。 (注意:“上面的none”选项与其他选项的切换在其他地方作为表单中的内置功能被处理 - Drupal Webform)

我正在努力(作为一个在旅途中学习的新手)通过避免为每个组重复相同的代码来缩短代码。我需要以某种方式将 class 的一部分设置为变量,并在每个组的计数和消息输入中重新使用它。

<fieldset>
Group 1 Qs:
<div class="eg1">
  <div>
    <input class="adftg_eg1" type="checkbox" value="q1"> Text here 1
  </div>
  <div>
    <input class="adftg_eg1" type="checkbox" value="q2"> Text here 2
  </div>
  <div>
    <input class="adftg_eg1" type="checkbox" value="q3"> Text here 3
  </div>
  <div>
    <input class="adftg_eg1" type="checkbox" value="q4"> Text here 4
  </div>
  <div>
    <input class="adftg_eg1" type="checkbox" value="none"> none of the above
  </div>

</div>
</fieldset>
<br>
<fieldset>
Group 2 Qs:
<div class="sth1">
  <div>
    <input class="adftg_sth1" type="checkbox" value="q1"> Text here 1
  </div>
  <div>
    <input class="adftg_sth1" type="checkbox" value="q2"> Text here 2
  </div>
  <div>
    <input class="adftg_sth1" type="checkbox" value="q3"> Text here 3
  </div>
  <div>
    <input class="adftg_sth1" type="checkbox" value="q4"> Text here 4
  </div>
  <div>
    <input class="adftg_sth1" type="checkbox" value="none"> none of the above
  </div>

</div>
</fieldset>
:: RESULTS :: <br>
<div class="results-wrapper" style="font-weight: bold;"> Group 1 Results:
  <div>
    Count a: <input class="eg1_count" name="eg1_count" value="" size="30" maxlength="50">
  </div>
  <div>
    Message a: <input class="eg1_msg" name="eg1_msg" value="" size="30" maxlength="50">
  </div>
</div>
<br><br>
<div class="results-wrapper" style="font-weight: bold;"> Group 2 Results:
  <div>
    Count a: <input class="sth1_count" name="sth1_count" value="" size="30" maxlength="50">
  </div>
  <div>
    Message a: <input class="sth1_msg" name="sth1_msg" value="" size="30" maxlength="50">
  </div>
</div>
<br><br>

这是前 2 组的 jQuery 代码:

    $('input[class^=adftg][value^=q]').change(function() {
      var a = $('input[class^=adftg][value^=q]:checked').length
      $('.eg1_count').val(a);
      var msg = '0';
      var msgbox = $('.eg1_msg')
    
      if (a < 3 && a > 0) {
        var msg = 'msg for 1 or 2 count in group EG1';
      } else if (a >= 3) {
        var msg = 'msg for 3 more count in group EG1';
      } else {
        var msg = ('msg for none selected');
      }
      (msgbox).val(msg);
    });
    // if "none of the above" is checked set the count to '0' and give a message
    $('input[class^=adftg][value=none]').change(function() {
      $('.eg1_count').val(0);
      $('.eg1_msg').val('msg for none of the above in group EG1');
    });
// second group
    $('input[class^=adftg][value^=q]').change(function() {
      var a = $('input[class^=adftg][value^=q]:checked').length
      $('.sth1_count').val(a);
      var msg = '0';
      var msgbox = $('.sth1_msg')
    
      if (a < 3 && a > 0) {
        var msg = 'msg for 1 or 2 count in group STH1';
      } else if (a >= 3) {
        var msg = 'msg for 3 more count in group STH1';
      } else {
        var msg = ('msg for none selected');
      }
      (msgbox).val(msg);
    });

//  if "none of the above" is checked set the count to '0' and give a message
    $('input[class^=adftg][value=none]').change(function() {
      $('.sth1_count').val(0);
      $('.sth1_msg').val('msg for none of the above in group STH1');
    });

编辑: 鉴于@Swati 和@cars10m 分享的前 2 个答案以及他们处理任务的想法(对我来说是新的),请注意我的表格比我在上面尝试演示的要长且复杂。每个问题集的结果包装器与许多其他 div 的实际问题组分开。我可以移动它来跟随它的相关问题组,但我宁愿不。我期待一个基于我的第一个 jquery 代码的解决方案,但重新制作了,所以我不必一次又一次地重复相同的代码。然而,能够 div 容器 select 的想法非常有吸引力,并且可以让我更灵活地在其他地方重新使用代码来解决类似类型的问题(其中大量计算选中的复选框或页面上的收音机)。我乐于接受任何关于重组我的表单(一个长的 Drupal 多页 Web 表单)的最佳计划的建议,以使生活更轻松,代码更简单但更高效。

您可以在复选框周围添加 <div> 标记,这样我们就可以使用 $(this).closest('div') 一次只在 div 中查找复选框和其他输入。在下面的代码中,我有向某些 function 添加重复代码并传递 length 的值以获得所需的 message 并将该消息添加到所需的输入 .

演示代码 :

//on change of checkbox
$('input[type="checkbox"]').change(function() {
var name=  $(this).closest('div').attr('class')
  //if value is none 
  if ($(this).val() == "none") {
    //add reuqired count and message to input box
    $(this).closest('div').find("input[name='count']").val(0);
    $(this).closest('div').find("input[name='message']").val('msg for none of the above in group '+name);

  } else {
    //get slectore
    var selector = $(this).closest('div').find('input[type="checkbox"]');
    //get length
    var length = selector.filter(':checked').length;
    var msg = evaluate(length); //call function
    //add value to required inputs
    $(this).closest('div').find("input[name='message']").val(msg+""+name)
    $(this).closest('div').find("input[name='count']").val(length)

  }
});

function evaluate(a) {
  if (a < 3 && a > 0) {
    var msg = 'msg for 1 or 2 count in group ';
  } else if (a >= 3) {
    var msg = 'msg for 3 more count in group ';
  } else {
    var msg = ('msg for none selected');
  }

  return msg;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!--added div-->
<div class="EG1">
  <input class="adftg_eg1" type="checkbox" value="q1"> Text here 1 <br>
  <input class="adftg_eg1" type="checkbox" value="q2"> Text here 2 <br>
  <input class="adftg_eg1" type="checkbox" value="q3"> Text here 3 <br>
  <input class="adftg_eg1" type="checkbox" value="q4"> Text here 4 <br>
  <input class="adftg_eg1" type="checkbox" value="none"> none of the above <br> Count a: 
  <!--add name="count"-->
  <input class="eg1_count" name="count" value="" size="30" maxlength="50"><br><br> Message a: <input class="eg1_msg" name="message" value="" size="30" maxlength="50">
  <hr>
</div>
<div class="STH1">
  <input class="adftg_sth1" type="checkbox" value="q1"> Text here 1 <br>
  <input class="adftg_sth1" type="checkbox" value="q2"> Text here 2 <br>
  <input class="adftg_sth1" type="checkbox" value="q3"> Text here 3 <br>
  <input class="adftg_sth1" type="checkbox" value="q4"> Text here 4 <br>
  <input class="adftg_sth1" type="checkbox" value="none"> none of the above <br> Count b: <input class="sth1_count" name="count" value="" size="30" maxlength="50"><br><br> Message b: <input class="sth1_msg" name="message" value="" size="30" maxlength="50">
</div>

更新 1 :

在下面的演示代码中,我直接选择了输入并为其添加了值,因为我们已经有了 class eg1sth1,所以我们可以在这里使用它。

演示代码 :

//on change of checkbox
$('input[type="checkbox"]').change(function() {
  var name = $(this).closest('div').parent().attr('class')
  var classes= $(this).attr('class') //get class of checkbox
  //if value is none 
  if ($(this).val() == "none") {
   $("."+classes).not(this).prop('checked', false);//uncheck other
    $("input[name=" + name + "_count]").val(0);
    $("input[name=" + name + "_msg]").val('msg for none of the above in group ' + name);
  } else {
    var selector = $(this).closest('div').parent().find('input[type="checkbox"]');
    var length = selector.filter(':checked').length;
    var msg = evaluate(length); 
    //add value to required inputs
    $("input[name='" + name + "_msg']").val(msg + " " + name)
    $("input[name='" + name + "_count']").val(length)

  }
});

function evaluate(a) {
  if (a < 3 && a > 0) {
    var msg = 'msg for 1 or 2 count in group ';
  } else if (a >= 3) {
    var msg = 'msg for 3 more count in group ';
  } else {
    var msg = ('msg for none selected');
  }

  return msg;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<fieldset>
  Group 1 Qs:
  <div class="eg1">
    <div>
      <input class="adftg_eg1" type="checkbox" value="q1"> Text here 1
    </div>
    <div>
      <input class="adftg_eg1" type="checkbox" value="q2"> Text here 2
    </div>
    <div>
      <input class="adftg_eg1" type="checkbox" value="q3"> Text here 3
    </div>
    <div>
      <input class="adftg_eg1" type="checkbox" value="q4"> Text here 4
    </div>
    <div>
      <input class="adftg_eg1" type="checkbox" value="none"> none of the above
    </div>

  </div>
</fieldset>
<br>
<fieldset>
  Group 2 Qs:
  <div class="sth1">
    <div>
      <input class="adftg_sth1" type="checkbox" value="q1"> Text here 1
    </div>
    <div>
      <input class="adftg_sth1" type="checkbox" value="q2"> Text here 2
    </div>
    <div>
      <input class="adftg_sth1" type="checkbox" value="q3"> Text here 3
    </div>
    <div>
      <input class="adftg_sth1" type="checkbox" value="q4"> Text here 4
    </div>
    <div>
      <input class="adftg_sth1" type="checkbox" value="none"> none of the above
    </div>

  </div>
</fieldset>
:: RESULTS :: <br>
<div class="results-wrapper" style="font-weight: bold;"> Group 1 Results:
  <div>
    Count a: <input class="eg1_count" name="eg1_count" value="" size="30" maxlength="50">
  </div>
  <div>
    Message a: <input class="eg1_msg" name="eg1_msg" value="" size="30" maxlength="50">
  </div>
</div>
<br><br>
<div class="results-wrapper" style="font-weight: bold;"> Group 2 Results:
  <div>
    Count a: <input class="sth1_count" name="sth1_count" value="" size="30" maxlength="50">
  </div>
  <div>
    Message a: <input class="sth1_msg" name="sth1_msg" value="" size="30" maxlength="50">
  </div>
</div>
<br><br>

编辑 2:
好的,就在这里。我再次调整了我的答案以处理更新的和更现实的 HTML 结构。请再次检查。

我做了以下修改:

  • 首先我创建了两个 jQuery 对象 Q(所有问题)和 A(所有答案)
  • 在事件处理程序中,我识别 res 的基础是答案在 jQuery 对象中具有 与问题相同的内部位置 它的 jQuery 对象:
    let res=A.eq(Q.index(div[0])).find('input');

脚本的其余部分将照常运行。

const Q=$('fieldset > div');      // all question divs
const A=$('div.results-wrapper'); // all answer divs
//on change of checkbox
$('input[type="checkbox"]').change(function() {
  const div=$(this).closest('div').parent();
  div.find('[type=checkbox][value'+(this.value=="none"?'!':'')+'=none]')
     .prop('checked',false); // mimic a radio-button-loke behaviour
  let cnt=div.find('[type=checkbox][value!=none]:checked').length;
  let res=A.eq(Q.index(div[0])).find('input');
  if (true) { res[0].value=cnt;
  res[1].value=
   (cnt? cnt<3 ? 'Fewer than 3'
               : '3 or more'
       : 'No') 
   +' boxes checked.' ;
   }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- changed again, after OP provided update -->
<fieldset>
Group 1 Qs:
<div class="eg1">
  <div>
    <input class="adftg_eg1" type="checkbox" value="q1"> Text here 1
  </div>
  <div>
    <input class="adftg_eg1" type="checkbox" value="q2"> Text here 2
  </div>
  <div>
    <input class="adftg_eg1" type="checkbox" value="q3"> Text here 3
  </div>
  <div>
    <input class="adftg_eg1" type="checkbox" value="q4"> Text here 4
  </div>
  <div>
    <input class="adftg_eg1" type="checkbox" value="none"> none of the above
  </div>

</div>
</fieldset>
<br>
<fieldset>
Group 2 Qs:
<div class="sth1">
  <div>
    <input class="adftg_sth1" type="checkbox" value="q1"> Text here 1
  </div>
  <div>
    <input class="adftg_sth1" type="checkbox" value="q2"> Text here 2
  </div>
  <div>
    <input class="adftg_sth1" type="checkbox" value="q3"> Text here 3
  </div>
  <div>
    <input class="adftg_sth1" type="checkbox" value="q4"> Text here 4
  </div>
  <div>
    <input class="adftg_sth1" type="checkbox" value="none"> none of the above
  </div>

</div>
</fieldset>
:: RESULTS :: <br>
<div class="results-wrapper" style="font-weight: bold;"> Group 1 Results:
  <div>
    Count a: <input class="eg1_count" name="eg1_count" value="" size="30" maxlength="50">
  </div>
  <div>
    Message a: <input class="eg1_msg" name="eg1_msg" value="" size="30" maxlength="50">
  </div>
</div>
<br><br>
<div class="results-wrapper" style="font-weight: bold;"> Group 2 Results:
  <div>
    Count a: <input class="sth1_count" name="sth1_count" value="" size="30" maxlength="50">
  </div>
  <div>
    Message a: <input class="sth1_msg" name="sth1_msg" value="" size="30" maxlength="50">
  </div>
</div>
<br><br>

我首先处理的逻辑是可以检查一个或多个文本选项“none”选项.在这两种情况下,必须删除当前部分中所有“其他”性质的复选标记。

之后我简单地计算 :checked 个复选框并将结果放入计数和消息 input-fields 中。不需要 evaluate() 函数,因为这可以在带有两个三元运算符 (condition ? whentrue : whenfalse) 的 one-liner 中轻松完成。

div.find('[type=checkbox][value'+(this.value=="none"?'!':'')+'=none]')

值得仔细研究:根据当前单击的复选框是否具有值 =="none" 我将 '!''' (空字符串)添加到选择器字符串,这将然后是:

'[type=checkbox][value!=none]'  // for this.value=="none"
'[type=checkbox][value=none]'   // for this.value!="none"