简体   繁体   中英

Why don't all my checkboxes have the same behavior?

I'm adding some interactivity to a form.

A user will select from a range of activities. Some of the activities have a time-clash.

If a user selects one of the activities with a time-clash, then the activity it clashes with will be disabled and unable to be selected.

If the user then DEselects that checkbox, then they are all enabled and are free to choose any checkbox they want.

Right now, I can disable all the correct boxes. But I am unable to disable them again, aside from the first, frameworks. With the others, I am locked with my decision and have to refresh the page. Why is this happening?

Here is my code:

Javascript

// Register for Activities section of the form.
document.querySelector(".activities").addEventListener("change", function() {
  var main = document.getElementById("all");
  var framework = document.getElementById("framework");
  var libs = document.getElementById("libs");
  var express = document.getElementById("express");
  var node = document.getElementById("node");
  var build = document.getElementById("build");
  var npm = document.getElementById("npm");
  var frameworkLbl = document.getElementById("frameworkLabel");
  var libsLbl = document.getElementById("libsLabel");
  var expressLbl = document.getElementById("expressLabel");
  var nodeLbl = document.getElementById("nodeLabel");

  // If the user selects a workshop, don't allow selection of a workshop at the same date and time -- you should disable the checkbox and visually indicate that the workshop in the competing time slot isn't available.
  if(framework.checked == true) {
    express.disabled = true;
    expressLbl.style.color = "grey";
  } else if(express.checked == true) {
    framework.disabled = true;
    frameworkLbl.style.color = "grey";
  } else if(libs.checked == true) {
    node.disabled = true;
    nodeLbl.style.color = "grey";
  } else if(node.checked == true) {
    libs.disabled = true;
    libsLbl.style.color = "grey";
  }

  // When a user unchecks an activity, make sure that competing activities (if there are any) are no longer disabled.
  if(framework.checked == false) {
    express.disabled = false;
    expressLbl.style.color = "black";
  } else if(express.checked == false) {
    framework.disabled = false;
    frameworkLbl.style.color = "black";
  } else if(libs.checked == false) {
    node.disabled = false;
    nodeLbl.style.color = "black";
  } else if(node.checked == false) {
    libs.disabled = false;
    libsLbl.style.color = "black";
  }
});

HTML

<fieldset class="activities">
  <legend>Register for Activities</legend>
  <div id="activityReminder"></div>
  <div id="lineBreak"></div>
  <label><input type="checkbox" name="all" id="all" class="activity"> Main Conference — $200</label>
  <label id="frameworkLabel"><input type="checkbox" name="js-frameworks" id="framework" class="activity"> JavaScript Frameworks Workshop — Tuesday 9am-12pm, $100</label>
  <label id="libsLabel"><input type="checkbox" name="js-libs" id="libs" class="activity"> JavaScript Libraries Workshop — Tuesday 1pm-4pm, $100</label>
  <label id="expressLabel"><input type="checkbox" name="express" id="express" class="activity"> Express Workshop — Tuesday 9am-12pm, $100</label>
  <label id="nodeLabel"><input type="checkbox" name="node" id="node" class="activity"> Node.js Workshop — Tuesday 1pm-4pm, $100</label>          
  <label><input type="checkbox" name="build-tools" id="build" class="activity"> Build tools Workshop — Wednesday 9am-12pm, $100</label>
  <label><input type="checkbox" name="npm" id="npm" class="activity"> npm Workshop — Wednesday 1pm-4pm, $100</label>
</fieldset>

your checkbox and dependent checkbox group are supposed to be independent of other checkbox groups.

The implication of your else if statements is that you have made all of them dependent on each other. They are supposed to be separate if statements.

So, a working correction is

// Register for Activities section of the form.
document.querySelector(".activities").addEventListener("change", function(){
    var main = document.getElementById("all");
    var framework = document.getElementById("framework");
    var libs = document.getElementById("libs");
    var express = document.getElementById("express");
    var node = document.getElementById("node");
    var build = document.getElementById("build");
    var npm = document.getElementById("npm");

    var frameworkLbl = document.getElementById("frameworkLabel");
    var libsLbl = document.getElementById("libsLabel");
    var expressLbl = document.getElementById("expressLabel");
    var nodeLbl = document.getElementById("nodeLabel");


    // If the user selects a workshop, don't allow selection of a workshop at the same date and time -- you should disable the checkbox and visually indicate that the workshop in the competing time slot isn't available.
    if(framework.checked == true) {
        express.disabled = true;
        expressLbl.style.color = "grey";
    }
    if(express.checked == true) {
        framework.disabled=  true;
        frameworkLbl.style.color = "grey";
    }
    if(libs.checked == true) {
        node.disabled = true;
        nodeLbl.style.color = "grey";
    }
    if(node.checked == true) {
        libs.disabled = true;
        libsLbl.style.color = "grey";
    } 

    // When a user unchecks an activity, make sure that competing activities (if there are any) are no longer disabled.
    if(framework.checked == false) {
        express.disabled = false;
        expressLbl.style.color = "black";
    }
    if(express.checked == false) {
        framework.disabled = false;
        frameworkLbl.style.color = "black";
    }
    if(libs.checked == false) {
        node.disabled = false;
        nodeLbl.style.color = "black";
    }
    if(node.checked == false) {
        libs.disabled = false;
        libsLbl.style.color = "black";
    }
});

Change your if else 's to if 's. They are being overlooked as they're chained to if(framework.checked == false) and if(framework.checked == true)

Syntax Error

In some browsers elem.disabled not working, so: To disable checkbox in HTML you only have to add the disabled attribute, and to enable it again you must remove the disabled attribute and NOT to assign false

Solution

 // Register for Activities section of the form. document.querySelector(".activities").addEventListener("change", function() { var main = document.getElementById("all"); var framework = document.getElementById("framework"); var libs = document.getElementById("libs"); var express = document.getElementById("express"); var node = document.getElementById("node"); var build = document.getElementById("build"); var npm = document.getElementById("npm"); var frameworkLbl = document.getElementById("frameworkLabel"); var libsLbl = document.getElementById("libsLabel"); var expressLbl = document.getElementById("expressLabel"); var nodeLbl = document.getElementById("nodeLabel"); // If the user selects a workshop, don't allow selection of a workshop at the same date and time -- you should disable the checkbox and visually indicate that the workshop in the competing time slot isn't available. if(framework.checked == true) { //express.disabled = true; disableElement(express); expressLbl.style.color = "grey"; } else if(express.checked == true) { //framework.disabled = true; disableElement(framework); frameworkLbl.style.color = "grey"; } else if(libs.checked == true) { //node.disabled = true; disableElement(node); nodeLbl.style.color = "grey"; } else if(node.checked == true) { //libs.disabled = true; disableElement(libs); libsLbl.style.color = "grey"; } // When a user unchecks an activity, make sure that competing activities (if there are any) are no longer disabled. if(framework.checked == false) { //express.disabled = false; enableElement(express); expressLbl.style.color = "black"; } // else if(express.checked == false) { //framework.disabled = false; enableElement(framework); frameworkLbl.style.color = "black"; } // else if(libs.checked == false) { //node.disabled = false; enableElement(node); nodeLbl.style.color = "black"; } // else if(node.checked == false) { //libs.disabled = false; enableElement(libs); libsLbl.style.color = "black"; } console.log("express.checked=" +(express.checked)); }); function disableElement(elem){ var att = document.createAttribute("disabled"); // Create a "disabled" attribute elem.setAttributeNode(att); } function enableElement(elem){ elem.removeAttribute("disabled"); } 
 <fieldset class="activities"> <legend>Register for Activities</legend> <div id="activityReminder"></div> <div id="lineBreak"></div> <label><input type="checkbox" name="all" id="all" class="activity"> Main Conference — $200</label> <label id="frameworkLabel"><input type="checkbox" name="js-frameworks" id="framework" class="activity"> JavaScript Frameworks Workshop — Tuesday 9am-12pm, $100</label> <label id="libsLabel"><input type="checkbox" name="js-libs" id="libs" class="activity"> JavaScript Libraries Workshop — Tuesday 1pm-4pm, $100</label> <label id="expressLabel"><input type="checkbox" name="express" id="express" class="activity"> Express Workshop — Tuesday 9am-12pm, $100</label> <label id="nodeLabel"><input type="checkbox" name="node" id="node" class="activity"> Node.js Workshop — Tuesday 1pm-4pm, $100</label> <label><input type="checkbox" name="build-tools" id="build" class="activity"> Build tools Workshop — Wednesday 9am-12pm, $100</label> <label><input type="checkbox" name="npm" id="npm" class="activity"> npm Workshop — Wednesday 1pm-4pm, $100</label> </fieldset> 

There's significant opportunity to DRY your code up. For example , if you use an array to track competing timeslots, you can avoid the verbose use of variables and logic blocks by relying upon your naming conventions:

var timeslots = [['framework','express'],['libs','node'],['build'],['npm']];

document.querySelector(".activities").addEventListener("change", function(e){
    timeslots.filter(function(slot){
      return slot.indexOf(e.target.id) > -1;
    })[0].forEach(function(lecture){
      var checkbox = document.getElementById(lecture);
      var label = document.getElementById(lecture+'Label');
      // deactivate competing
      if( e.target.checked == true ) {
        if( lecture != e.target.id ) {
           checkbox.disabled = true;
           label.style.color = 'grey';
        }
      } else { //reactivate competing
        if( lecture != e.target.id ) {
           checkbox.disabled = false;
           label.style.color = 'black';
        }
      }
    });
});

Here we use Array#filter to find the timeslot our changed checkbox lives within. We're able to do so by using the event.target that we are capturing via the anonymous callback passed to the change listener (we're calling the local variable e here, by convention).

Presuming that a lecture exists in only one timeslot, we get the first position returned by filter and loop over each inner array with Array#forEach . We then activate or deactivate all competing checkboxes and labels using your naming convention. This will make your JavaScript code more maintainable, by simply modifying the timeslots array should your HTML form ever require updating.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM