I have multiple checkboxes and multiple text inputs. If a checkbox gets checked the text input next to it needs to be enabled

Viewed 344

So I have multiple checkboxes that are unchecked by default. Next to each checkbox I have a disabled text input. And you probably already know where I am heading with this. I want to enable a text input whenever the checkbox next to it has been checked. HOWEVER here's the catch.

The entirety of this html is constructed using javascript. So my script creates all the checkboxes and text inputs. This makes it harder for me to target a specific checkbox and the text input next to it. I'll show the code below so you can understand what I am talking about.

HTML CODE

<fieldset>
    <legend>Order details</legend>
    <div class="container">
        <div class="row">
            <div class="span7" id="woodTypes">
            </div>
        </div>
    </div>
    <div class="span4 valid">
        <div id="orderMessages" hidden class="alert alert-error">
            <ul id="orderMessageList">
            </ul>
        </div>
    </div>
    <div class="span1"></div>
    </div>
    <div class="form-actions">
        <button id="send" class="btn btn-success" type="button">Send</button>
    </div>
    </div>
</fieldset>

JAVASCRIPT CODE

"use strict"
const woodList = document.getElementById('woodTypes');


async function readWoodTypes() {
    const response = await fetch("woodtypes.json");
    if (response.ok) {
        const woodtypes = await response.json();
        transferWoodTypes(woodtypes);
    } else {
        console.log("Oops, something went wrong!");
    }
}

function transferWoodTypes(woodtypes) {
    for (const woodtype of woodtypes) {
        addWoodtypeToList(woodtype);
    }
}

function addWoodtypeToList(woodtype) {
    let divControlGroup = document.createElement('div');
    divControlGroup.className = "control-group";
    woodList.appendChild(divControlGroup);
    let label = document.createElement("label");
    label.className = "control-label";
    label.innerText = woodtype.name + ' ';
    divControlGroup.appendChild(label);
    let inputCheckBox = document.createElement("input");
    inputCheckBox.id = "chk_" + `${woodtype.name}`;
    inputCheckBox.type = "checkbox";
    label.appendChild(inputCheckBox);
    let divControls = document.createElement("div");
    divControls.className = "controls";
    divControlGroup.appendChild(divControls);
    let divInput = document.createElement("div");
    divInput.className = "input-append";
    divControls.appendChild(divInput);
    let inputTekst = document.createElement("input");
    inputTekst.className = "inpbox input-mini";
    inputTekst.required = "";
    inputTekst.type = "number";
    inputTekst.min = "1";
    inputTekst.id = woodtype.name;
    inputTekst.name = woodtype.name;
    inputTekst.disabled = "true";
    divInput.appendChild(inputTekst);
    let span = document.createElement("span");
    span.className = "add-on";
    span.innerText = woodtype.unit;
    divInput.appendChild(span);
}

JSON FILE

[
    {
        "name": "bangkirai",
        "unit": "pieces"
    },
    {
        "name": "birch",
        "unit": "pieces"
    },
    {
        "name": "pine",
        "unit": "pieces"
    },
    {
        "name": "oak",
        "unit": "pieces"
    },
    {
        "name": "chestnut",
        "unit": "pieces"
    },
    {
        "name": "limewood",
        "unit": "pieces"
    },
    {
        "name": "walnut",
        "unit": "pieces"
    },
    {
        "name": "rubberwood",
        "unit": "pieces"
    },
    {
        "name": "cedar",
        "unit": "kg"
    }
]

So as you can see I am creating the order list entirely using javascript with data from a json file.

I have tried looking for the solution for days but I am desperate now so that's why im posting it here.

I think the closest I got was looping over every checkbox using query selector all.

Like so:

let checkboxes = document.querySelectorAll("input[type='checkbox']")
for (const checkbox of checkboxes) { //do something with the checkbox}

this however didn't work for me.

Anyone got any tips for me?

To summarize, if a checkbox gets checked the text input next to it should be enabled.

Thanks in advance :)

3 Answers

You can add this:

let checkboxes = document.querySelectorAll("input[type='checkbox']");
for (const checkbox of checkboxes) {
  checkbox.addEventListener("change", function(){  
      let classSelected = this.parentNode.childNodes[0].data;
      let input = document.querySelector("."+classSelected);
    input.disabled = !checkbox.checked;
  })
}

"use strict"
const woodList = document.getElementById('woodTypes');
let woodtypes = [{
    "name": "bangkirai",
    "unit": "pieces"
  },
  {
    "name": "birch",
    "unit": "pieces"
  },
  {
    "name": "pine",
    "unit": "pieces"
  },
  {
    "name": "oak",
    "unit": "pieces"
  },
  {
    "name": "chestnut",
    "unit": "pieces"
  },
  {
    "name": "limewood",
    "unit": "pieces"
  },
  {
    "name": "walnut",
    "unit": "pieces"
  },
  {
    "name": "rubberwood",
    "unit": "pieces"
  },
  {
    "name": "cedar",
    "unit": "kg"
  }
]

transferWoodTypes(woodtypes);

function transferWoodTypes(woodtypes) {
  for (const woodtype of woodtypes) {
    addWoodtypeToList(woodtype);
  }
}

function addWoodtypeToList(woodtype) {
  let divControlGroup = document.createElement('div');
  divControlGroup.className = "control-group";
  woodList.appendChild(divControlGroup);
  let label = document.createElement("label");
  label.className = "control-label";
  label.innerText = woodtype.name + ' ';
  divControlGroup.appendChild(label);
  let inputCheckBox = document.createElement("input");
  inputCheckBox.id = "chk_" + `${woodtype.name}`;
  inputCheckBox.type = "checkbox";
  label.appendChild(inputCheckBox);
  let divControls = document.createElement("div");
  divControls.className = "controls";
  divControlGroup.appendChild(divControls);
  let divInput = document.createElement("div");
  divInput.className = "input-append";
  divControls.appendChild(divInput);
  let inputTekst = document.createElement("input");
  inputTekst.className = "inpbox input-mini" + " " + woodtype.name;
  inputTekst.required = "";
  inputTekst.type = "number";
  inputTekst.min = "1";
  inputTekst.id = woodtype.name;
  inputTekst.name = woodtype.name;
  inputTekst.disabled = "true";
  divInput.appendChild(inputTekst);
  let span = document.createElement("span");
  span.className = "add-on";
  span.innerText = woodtype.unit;
  divInput.appendChild(span);
}

let checkboxes = document.querySelectorAll("input[type='checkbox']");
for (const checkbox of checkboxes) {
  checkbox.addEventListener("change", function() {
    let classSelected = this.parentNode.childNodes[0].data;
    let input = document.querySelector("." + classSelected);
    input.disabled = !checkbox.checked;
  })
}
<fieldset>
  <legend>Order details</legend>
  <div class="container">
    <div class="row">
      <div class="span7" id="woodTypes">
      </div>
    </div>
  </div>
  <div class="span4 valid">
    <div id="orderMessages" hidden class="alert alert-error">
      <ul id="orderMessageList">
      </ul>
    </div>
  </div>
  <div class="span1"></div>
  </div>
  <div class="form-actions">
    <button id="send" class="btn btn-success" type="button">Send</button>
  </div>
  </div>
</fieldset>

You need to add change handler to the checkboxes. Like this:

/* Add this event handler */
inputCheckBox.addEventListener('change', (event) => {
      let closestInp = event.currentTarget.parentElement.parentElement.querySelectorAll('.inpbox');
      closestInp[0].disabled = !event.currentTarget.checked; 
});
/********/

Here is a working example:

"use strict"
const woodList = document.getElementById('woodTypes');
readWoodTypes();

function readWoodTypes() {
    const result = [
    {
        name: "bangkirai",
        unit: "pieces"
    },
    {
        name: "birch",
        unit: "pieces"
    },
    {
        name: "pine",
        unit: "pieces"
    },
    {
        name: "oak",
        unit: "pieces"
    },
    {
        name: "chestnut",
        unit: "pieces"
    },
    {
        name: "limewood",
        unit: "pieces"
    },
    {
        name: "walnut",
        unit: "pieces"
    },
    {
        name: "rubberwood",
        unit: "pieces"
    },
    {
        name: "cedar",
        unit: "kg"
    }
];

transferWoodTypes(result);
    /*const response = await fetch("woodtypes.json");
    if (response.ok) {
        const woodtypes = await response.json();
        transferWoodTypes(woodtypes);
    } else {
        console.log("Oops, something went wrong!");
    }*/
}

function transferWoodTypes(woodtypes) {
    for (const woodtype of woodtypes) {
        addWoodtypeToList(woodtype);
    }
}

function addWoodtypeToList(woodtype) {
    let divControlGroup = document.createElement('div');
    divControlGroup.className = "control-group";
    woodList.appendChild(divControlGroup);
    let label = document.createElement("label");
    label.className = "control-label";
    label.innerText = woodtype.name + ' ';
    divControlGroup.appendChild(label);
    let inputCheckBox = document.createElement("input");
    inputCheckBox.id = "chk_" + `${woodtype.name}`;
    inputCheckBox.type = "checkbox";
    /* Add this event handler */
    inputCheckBox.addEventListener('change', (event) => {
          let closestInp = event.currentTarget.parentElement.parentElement.querySelectorAll('.inpbox');
          closestInp[0].disabled = !event.currentTarget.checked; 
    });
    /********/
    label.appendChild(inputCheckBox);
    let divControls = document.createElement("div");
    divControls.className = "controls";
    divControlGroup.appendChild(divControls);
    let divInput = document.createElement("div");
    divInput.className = "input-append";
    divControls.appendChild(divInput);
    let inputTekst = document.createElement("input");
    inputTekst.className = "inpbox input-mini";
    inputTekst.required = "";
    inputTekst.type = "number";
    inputTekst.min = "1";
    inputTekst.id = woodtype.name;
    inputTekst.name = woodtype.name;
    inputTekst.disabled = "true";
    divInput.appendChild(inputTekst);
    let span = document.createElement("span");
    span.className = "add-on";
    span.innerText = woodtype.unit;
    divInput.appendChild(span);
}
<fieldset>
    <legend>Order details</legend>
    <div class="container">
        <div class="row">
            <div class="span7" id="woodTypes">
            </div>
        </div>
    </div>
    <div class="span4 valid">
        <div id="orderMessages" hidden class="alert alert-error">
            <ul id="orderMessageList">
            </ul>
        </div>
    </div>
    <div class="span1"></div>
    </div>
    <div class="form-actions">
        <button id="send" class="btn btn-success" type="button">Send</button>
    </div>
    </div>
</fieldset>

As you are creating each checkbox input you can set it up to do something on being checked/unchecked at that time.

Add an onchange event handler to each checkbox element. If it's checked then this sets the next sibling element (which is the input you are interested in) to enabled and if checked isn't set you set enabled to false.

Add this to the place where you are creating and setting up the checkbox element:

    inputCheckBox.onchange = "this.nextElementSibling.enabled = this.checked";

Here it is in your function:

function addWoodtypeToList(woodtype) {
    let divControlGroup = document.createElement('div');
    divControlGroup.className = "control-group";
    woodList.appendChild(divControlGroup);
    let label = document.createElement("label");
    label.className = "control-label";
    label.innerText = woodtype.name + ' ';
    divControlGroup.appendChild(label);
    let inputCheckBox = document.createElement("input");
    inputCheckBox.id = "chk_" + `${woodtype.name}`;
    inputCheckBox.type = "checkbox"; 
    //ADD THIS NEXT LINE
    inputCheckBox.onchange = "this.nextElementSibling.enabled = this.checked";
    label.appendChild(inputCheckBox);
    let divControls = document.createElement("div");
    divControls.className = "controls";
    divControlGroup.appendChild(divControls);
    let divInput = document.createElement("div");
    divInput.className = "input-append";
    divControls.appendChild(divInput);
    let inputTekst = document.createElement("input");
    inputTekst.className = "inpbox input-mini";
    inputTekst.required = "";
    inputTekst.type = "number";
    inputTekst.min = "1";
    inputTekst.id = woodtype.name;
    inputTekst.name = woodtype.name;
    inputTekst.disabled = "true";
    divInput.appendChild(inputTekst);
    let span = document.createElement("span");
    span.className = "add-on";
    span.innerText = woodtype.unit;
    divInput.appendChild(span);
}
Related