验证Vanilla JS中的多个单选按钮组

时间:2018-03-18 03:39:08

标签: javascript

我正在尝试使用pureJS验证多组单选按钮。基本上我的客户有一组约50个问题,每个问题都有4个单选按钮,可以用来挑选4个答案中的1个。

他们不想使用jQuery,但是pureJS,当只有一个问题时,我已经得到了以下工作,但是当有多个问题时,不会有任何帮助。

document.getElementById("submit_btn").addEventListener("click", function(event){
    var all_answered = true;
    var inputRadios = document.querySelectorAll("input[type=radio]")
    for(var i = 0; i < inputRadios.length; i++) {
        var name = inputRadios[i].getAttribute("name");
        if (document.getElementsByName(name)[i].checked) {
            return true;
            var all_answered = true;
        } else {
            var all_answered = false;
        }
    }
    if (!all_answered) {
        alert("Some questiones were not answered. Please check all questions and select an option.");
        event.preventDefault();
    }       
});

这些问题都是这样的 -

<div class="each-question">
<div class="unanswered-question">
    <div class="question-text">
        <div class="number">33</div>
        <div class="text">
                <p>Troubleshoot technology issues.</p>
        </div>
    </div>
    <div class="options" id="ans_285">
        <div class="radio-button">
            <input type="radio" value="3" id="ans33op1" name="ans_285">
            <label for="ans33op1" class="radio-label">Very Interested</label>
        </div>
        <div class="radio-button">
            <input type="radio" value="2" id="ans33op2" name="ans_285">
            <label for="ans33op2" class="radio-label">Interested</label>
        </div>
        <div class="radio-button">
            <input type="radio" value="1" id="ans33op3" name="ans_285" class="custom">
            <label for="ans33op3" class="radio-label"> Slightly Interested</label>
        </div>
        <div class="radio-button">
            <input type="radio" value="0" id="ans33op4" name="ans_285">
            <label for="ans33op4" class="radio-label"> Not Interested</label>
        </div>
    </div>
</div>

这是客户端使用的原始jQuery,现在必须是pureJS

    jQuery(document).ready(function () {
    jQuery("#question_list").submit(function () {
        var all_answered = true;
        jQuery("input:radio").each(function () {
            var name = jQuery(this).attr("name");
            if (jQuery("input:radio[name=" + name + "]:checked").length == 0) {
                all_answered = false;
            }
        });
        if (!all_answered) {
            alert("Some questiones were not answered. Please check all questions and select an option.");
            return false;
        }
    });
});

3 个答案:

答案 0 :(得分:0)

for条款中的所有内容都没有意义。这就是原因:

  • 由于你已经拥有inputRadios,所以没有任何意义并获取他们的名字,然后使用它来按名称获取元素,因为你已经拥有它们。

  • 由于您使用return true,因此功能退出,其后的所有内容都会被忽略。

  • 不是更新现有的all_answered变量,而是创建一个新的本地变量,一旦当前迭代结束就会丢失。

你应该做什么:

  1. 不是获取所有输入,而是获取所有答案,包含每个答案的输入的div.options元素,并迭代这些元素。

  2. 然后,使用答案的id,因为它与输入的名称相同,以获取相关输入。

  3. 使用some确保组中有选中的输入。然后,检查是否没有并停止循环。您找到了一个悬而未决的问题。

  4. <强>段:

    &#13;
    &#13;
    document.getElementById("submit_btn").addEventListener("click", function(event) {
      var
        /* Create a flag set by default to true. */
        all_answered = true,
    
        /* Get all answers. */
        answers = document.querySelectorAll(".options[id ^= ans_]");
    
      /* Iterate over every answer. */
      for (var i = 0; i < answers.length; i++) {
        var
          /* Use the id of the answer to get its radiobuttons. */
          radios = document.querySelectorAll("[name = " + answers[i].id + "]"),
    
          /* Save whether there is a checked input for the answer. */
          hasChecked = [].some.call(radios, function(radio) {
            return radio.checked;
          });
    
        /* Check whether there is a checked input for the answer or not. */
        if (!hasChecked) {
          /* Set the all_answered flag to false and break the loop. */
          all_answered = false;
          break;
        }
      }
    
      /* Check whether not all answers have been answered. */
      if (!all_answered) {
        console.log("Some questions were not answered...");
      } else {
        console.log("All questions are answered!");
      }
    });
    &#13;
    .question { display: inline-block }
    &#13;
    <div class="question">
      <div class="text">
        <p>Troubleshoot technology issues.</p>
      </div>
      <div class="options" id="ans_285">
        <div class="radio-button">
          <input type="radio" value="3" id="ans33op1" name="ans_285">
          <label for="ans33op1" class="radio-label">Very Interested</label>
        </div>
        <div class="radio-button">
          <input type="radio" value="2" id="ans33op2" name="ans_285">
          <label for="ans33op2" class="radio-label">Interested</label>
        </div>
        <div class="radio-button">
          <input type="radio" value="1" id="ans33op3" name="ans_285" class="custom">
          <label for="ans33op3" class="radio-label">Slightly Interested</label>
        </div>
        <div class="radio-button">
          <input type="radio" value="0" id="ans33op4" name="ans_285">
          <label for="ans33op4" class="radio-label">Not Interested</label>
        </div>
      </div>
    </div>
    <div class="question">
      <div class="text">
        <p>Troubleshoot technology issues.</p>
      </div>
      <div class="options" id="ans_286">
        <div class="radio-button">
          <input type="radio" value="3" id="ans34op1" name="ans_286">
          <label for="ans34op1" class="radio-label">Very Interested</label>
        </div>
        <div class="radio-button">
          <input type="radio" value="2" id="ans34op2" name="ans_286">
          <label for="ans34op2" class="radio-label">Interested</label>
        </div>
        <div class="radio-button">
          <input type="radio" value="1" id="ans34op3" name="ans_286" class="custom">
          <label for="ans34op3" class="radio-label">Slightly Interested</label>
        </div>
        <div class="radio-button">
          <input type="radio" value="0" id="ans34op4" name="ans_286">
          <label for="ans34op4" class="radio-label">Not Interested</label>
        </div>
      </div>
    </div>
    <div class="question">
      <div class="text">
        <p>Troubleshoot technology issues.</p>
      </div>
      <div class="options" id="ans_287">
        <div class="radio-button">
          <input type="radio" value="3" id="ans35op1" name="ans_287">
          <label for="ans35op1" class="radio-label">Very Interested</label>
        </div>
        <div class="radio-button">
          <input type="radio" value="2" id="ans35op2" name="ans_287">
          <label for="ans35op2" class="radio-label">Interested</label>
        </div>
        <div class="radio-button">
          <input type="radio" value="1" id="ans35op3" name="ans_287" class="custom">
          <label for="ans35op3" class="radio-label">Slightly Interested</label>
        </div>
        <div class="radio-button">
          <input type="radio" value="0" id="ans35op4" name="ans_287">
          <label for="ans35op4" class="radio-label">Not Interested</label>
        </div>
      </div>
    </div>
    <button id="submit_btn">Submit</button>
    &#13;
    &#13;
    &#13;

答案 1 :(得分:0)

不确定该副本是否只是一个问题,但您的return true循环中有一个for,如果只有一个回答,则会导致整个函数返回true 。删除它会有所帮助。

忽略这一点,你的解决方案有点笨拙,因为它会单独循环遍历页面上的每一个输入,如果没有取消选中每个单选按钮,则会将其标记为假。

这是一种不同的方法。基本上,获取所有单选按钮,然后按问题将它们分组到数组中。然后,循环遍历每个阵列并检查每个组中是否至少有一个被回答。

&#13;
&#13;
document.querySelector('form').addEventListener('submit', e => {
  // Get all radio buttons, convert to an array.
  const radios = Array.prototype.slice.call(document.querySelectorAll('input[type=radio]'));
  
  // Reduce to get an array of radio button sets
  const questions = Object.values(radios.reduce((result, el) => 
    Object.assign(result, { [el.name]: (result[el.name] || []).concat(el) }), {}));
  
  // Loop through each question, looking for any that aren't answered.
  const hasUnanswered = questions.some(question => !question.some(el => el.checked));
  
  if (hasUnanswered) {
    console.log('Some unanswered');
  } else {
    console.log('All set');
  }
  
  e.preventDefault(); // just for demo purposes... normally, just put this in the hasUnanswered part
});
&#13;
<form action="#">
 <div>
  <label><input type="radio" name="a" /> A</label>
  <label><input type="radio" name="a" /> B</label>
  <label><input type="radio" name="a" /> C</label>
  <label><input type="radio" name="a" /> D</label>
 </div>
 <div>
  <label><input type="radio" name="b" /> A</label>
  <label><input type="radio" name="b" /> B</label>
  <label><input type="radio" name="b" /> C</label>
  <label><input type="radio" name="b" /> D</label>
 </div>
 <button type="submit">Submit</button>
</form>
&#13;
&#13;
&#13;

首先,我得到了所有带有收音机类型的收音机按钮(如果有其他收音机那样,我就不会打扰他们)。

然后,我使用NodeListquerySelectorAll()返回的Array转换为Array.prototype.slice.call(),然后将其NodeList。{/ p>

之后,我使用reduce()将问题分组在一起。我将它作为一个以元素名称为关键字的数组(因为我知道它们必须如何分组)。在减少之后,因为我并不真正关心它是一个带密钥的对象,所以我只使用Object.values()来获取数组。

之后,我在问题集上使用some()。如果返回true,则表示我至少有一个未回答的问题。

最后,在some()内,我在问题的各个单选按钮上做了另一个。为此,我想返回!some(),因为如果没有至少一个被回答,那么我应该总体上返回真实(我至少有一个问题没有回答)。

上面有点冗长。这个更简洁,是我可能在我自己的代码中使用的:

&#13;
&#13;
document.querySelector('form').addEventListener('submit', e => {
  if (Object.values(
    Array.prototype.reduce.call(
      document.querySelectorAll('input[type=radio]'),
      (result, el) => 
        Object.assign(result, { [el.name]: (result[el.name] || []).concat(el) }), 
      {}
    )
  ).some(q => !q.some(el => el.checked))) {
    e.preventDefault();
    console.log('Some questions not answered');
  }
});
&#13;
<form action="#">
 <div>
  <label><input type="radio" name="a" /> A</label>
  <label><input type="radio" name="a" /> B</label>
  <label><input type="radio" name="a" /> C</label>
  <label><input type="radio" name="a" /> D</label>
 </div>
 <div>
  <label><input type="radio" name="b" /> A</label>
  <label><input type="radio" name="b" /> B</label>
  <label><input type="radio" name="b" /> C</label>
  <label><input type="radio" name="b" /> D</label>
 </div>
 <button type="submit">Submit</button>
</form>
&#13;
&#13;
&#13;

答案 2 :(得分:0)

以下是简化版本,但应该有足够的代码让您朝着正确的方向前进。

&#13;
&#13;
var answer = [];
function checkAnswerCount(e) {
    // for the answer ids
    var i = 0, max = answer.length;
    // for the radios
    var j = 0; rMax = 0;
    // And a few extras
    var tmp = null, answerCount = 0;
    for(;i<max;i++) {
        tmp = document.getElementsByName(answer[i]);
        rMax = tmp.length;
        for(j=0;j<rMax;j++) {
            if (tmp[j].checked) {
                answerCount++;
                break;
            }
        }
    }
    if (answerCount == answer.length) {
        console.log("All questions have an answer, submit the form");
    } else {
        console.log("You need to answer all the questions");
    }
}

window.onload = function() {
    // each answer block is surrounded by the "options" class, 
    // so we use that to collect the ids of the raido groups
    var a = document.querySelectorAll(".options");
    var i = 0, max = a.length;
    for(;i<max;i++) {
        answer.push(a[i].id);
    }
    // And we want to check if all the answers have been answered
    // when the user tries to submit...
    var s = document.getElementById("submitAnswers");
    if (s) {
        s.addEventListener("click",checkAnswerCount,false);
    }
}
&#13;
<p>Question 1.</p>
<div class="options" id="ans_1">
    <label><input type="radio" name="ans_1" value="a1_1" /> Answer 1, op1</label>
    <label><input type="radio" name="ans_1" value="a1_2" /> Answer 1, op2</label>
</div>
<p>Question 2.</p>
<div class="options" id="ans_2">
    <label><input type="radio" name="ans_2" value="a2_1" /> Answer 2, op1</label>
    <label><input type="radio" name="ans_2" value="a2_2" /> Answer 2, op2</label>
</div>
<p>Question 3.</p>
<div class="options" id="ans_3">
    <label><input type="radio" name="ans_3" value="a3_1" /> Answer 3, op1</label>
    <label><input type="radio" name="ans_3" value="a3_2" /> Answer 3, op2</label>
</div>
<button id="submitAnswers">Submit / check</button>
&#13;
&#13;
&#13;