I tried to have two input option enable based on the radio button choice, but only one option is enabling not matter which option I choose. Eg- If I choose sheetcake, instead of having input option for sheetcake, I have the input option of roundcake. I am new in javascript and any advice will be much appreciated. Thank You. ( I tried to run the code in snippet and it works fine but I run the same code in browser and only one input box is working no matter what, I tried to run in 3 different browsers and got the same error, I don't know what is the issue and where I made a mistake. Thank You in advance.
const sheetcake = document.getElementById("sheetcake");
const roundcake = document.getElementById("roundcake");
var caketype = document.getElementsById("caketype");
function CakeChoice(choice){
if (choice == sheetcake){
document.getElementById("SheetLength").disabled=false;
document.getElementById("SheetWidth").disabled=false;
document.getElementById("RoundRadius").disabled=true;
}
else {
document.getElementById("SheetLength").disabled=true;
document.getElementById("SheetWidth").disabled=true;
document.getElementById("RoundRadius").disabled=false;
}
}
<div id="caketype">
<label class="caketype required">Cake Type:</label> <br>
<input type="radio" id="sheetcake" name="caketype" value="0" required onclick="CakeChoice(sheetcake)">
<label>Sheet Cake</label><br>
<input type="radio" id="roundcake" name="caketype" value="0" required onclick="CakeChoice(roundcake)">
<label>Round Cake</label>
</div>
<br>
<div id="CakeDimensions" >
<label>Cake size (cm)</label><br>
<input type="number" id="SheetLength" value="0" min="30" max="60" required disabled>
<label class="form-label required">cm Length</label><br>
<input type="number" id="SheetWidth" value="0" min="30" max="45" required disabled>
<label class="form-label required">cm Width</label>
</div>
<br>
<div id="round">
<label>Cake size</label><br>
<input type="number" id="RoundRadius" min="15" max="30" disabled required>
<label class="form-label required">cm Radius</label>
</div>
<br><br>
<div id="cakelayers">
<label class="form-label required">How many layers?</label><br>
<input type="radio" id="OneLayer" name="CakeLayers" value="1layer" required>
<label for="OneLayer">One Layer</label><br>
<input type="radio" id="TwoLayers" name="CakeLayers" value="2layers" required>
<label for="TwoLayers">Two Layers</label><br>
<input type="radio" id="ThreeLayers" name="CakeLayers" value="3layers" required>
<label for="ThreeLayers">Three Layers</label>
</div>
<br><br>
May I suggest a slightly alternative approach which avoids having irrelevant disabled options that some users might be trying to activate.
Instead of disabling the irrelevant options, manipulating the display styles of the two sets of option for cake dimensions (by javascript) allows for only the relevant one to be available for interaction. This lets you make the relevant size option only appear when a type has been chosen (and toggles between them if the user changes their mind).
As you have fairly complex markup for each option, I've added extra divisions containing each group. The ids for the relevant divisions, rectangle and round are used to create references to each grouping in the javascript allowing access to their style.display property, which can be toggled.
const sheetcake = document.getElementById("rectangle");
const roundcake = document.getElementById("round");
sheetcake.style = "display: none";
round.style = "display: none";
function CakeChoice(choice){
if (choice == 'sheetcake'){
sheetcake.style = "display: block";
roundcake.style = "display: none";
} else {
sheetcake.style = "display: none";
roundcake.style = "display: block";
}
}
<div id="caketype">
<label class="caketype required">Cake Type:</label> <br>
<input type="radio" id="sheetcake" name="caketype" value="0" required onclick="CakeChoice('sheetcake')">
<label>Sheet Cake</label><br>
<input type="radio" id="roundcake" name="caketype" value="0" required onclick="CakeChoice('roundcake')">
<label>Round Cake</label>
</div>
<br>
<div id="CakeDimensions" >
<div id="rectangle">
<label>Cake size (cm)</label><br>
<input type="number" id="SheetLength" value="0" min="30" max="60" required>
<label class="form-label required">cm Length</label><br>
<input type="number" id="SheetWidth" value="0" min="30" max="45" required>
<label class="form-label required">cm Width</label>
</div>
<div id="round">
<label>Cake size</label><br>
<input type="number" id="RoundRadius" min="15" max="30" required>
<label class="form-label" "required">cm Radius</label>
</div>
</div>
<br>
<div id="cakelayers">
<label class="form-label required">How many layers?</label><br>
<input type="radio" id="OneLayer" name="CakeLayers" value="1layer" required>
<label for="OneLayer">One Layer</label><br>
<input type="radio" id="TwoLayers" name="CakeLayers" value="2layers" required>
<label for="TwoLayers">Two Layers</label><br>
<input type="radio" id="ThreeLayers" name="CakeLayers" value="3layers" required>
<label for="ThreeLayers">Three Layers</label>
</div>
<br>
I've made some minor refactoring to your HTML then removed a bit of replication to your javascript, reducing the dependencies on Ids. This will make it more flexible should you add more options for dimensions or round. I've also illustrated adding the event listeners via javascript.
//Get all the radio buttons in the element with ID caketype and itterate them
document.querySelectorAll("#caketype input[type=radio]").forEach(function(item) {
//Add an on click event listener
item.addEventListener("click", function() {
//Is Sheet cake chosen from the clicked element
let isSheetCake = this.value === "sheetcake";
//Set out disabled AND required attributes based on the above
//Get the input elements in the fieldset and itterate instead of being bound by id
document.querySelectorAll("#CakeDimensions input").forEach(function(element) {
element.disabled = !isSheetCake;
element.required = isSheetCake;
});
//Do the same for round, but invert the logic
document.querySelectorAll("#round input").forEach(function(element) {
element.disabled = isSheetCake;
element.required = !isSheetCake;
});
//Bonus: lets set a class to indicate that group is disabled
//.classList.toggle() ,adds or removes a class, in this case
// based on a truthy value
document.getElementById("CakeDimensions").classList.toggle("disabled", !isSheetCake);
document.getElementById("round").classList.toggle("disabled", isSheetCake);
});
});
fieldset {
border: none;
padding: 0.5em;
margin: 0;
}
.disabled {
color: #EEE;
}
<!-- Ive Given the radio buttond values, which you are going to want if you send this to a server-->
<!-- Also encapsulated the radio button group with a fieldset which is more semantic-->
<!-- Inline Javascript has been removed -->
<!-- Labels have been associated with their form elements with the "for" attribute-->
<fieldset id="caketype">
<label class="caketype required">Cake Type:</label> <br>
<input type="radio" id="sheetcake" name="caketype" value="sheetcake" required>
<label for="sheetcake">Sheet Cake</label><br>
<input type="radio" id="roundcake" name="caketype" value="roundcake" required>
<label for="roundcake">Round Cake</label>
</fieldset>
<fieldset id="CakeDimensions">
<label>Cake size (cm)</label><br>
<input type="number" id="SheetLength" value="0" min="30" max="60" required disabled>
<label class="form-label required">cm Length</label><br>
<input type="number" id="SheetWidth" value="0" min="30" max="45" required disabled>
<label class="form-label required">cm Width</label>
</fieldset>
<fieldset id="round">
<label>Cake size</label><br>
<input type="number" id="RoundRadius" min="15" max="30" disabled required>
<label class="form-label required">cm Radius</label>
</fieldset>
Between Jon P's and Dave Pritlove's answers it looks like the basics are already covered. Tihs answer will focus on the following:
Event delegation: A programming paradigm in which event bubbling is used to leverage control of an unlimited number of elements by binding an ancestor element to listen for events and delegate which elements react to events and which elements are excluded.
HTMLFormElement interface: Part of the The HTML DOM API, that has terse syntax and unique features:
Referencing a form:
<form id="UI"></form>
const UI = document.forms.UI
/*or*/
const UI = document.forms[0] // the first of one or more forms.
Referencing all form controls✻ within UI with the .elements property:
<input id='i1' name='IO'> <button name='btn'></button> <input id='i2' name='IO'>
const fC = UI.elements;
// Reference by #id
const I1 = fC.i1 // first input by #id
// Refernce by [name]
const B = fC.btn // button by [name]
// HTMLFormsControlCollection of all tags with [name='IO']
const io = fC.IO // an array-like object of both inputs
const ioArray = [...io] // convert into an array
[for] attribute & .labels property association: Besides the [for] attribute & form control #id association, there's another type of association we can establish:
<label for='A'></label><input id='A'><label for='A'>I'm the 2nd label</label>
const IO = UI.elements; // collect all of #UI form controls
const a = IO.A; // reference the input
const Alabels = a.labels; // collect all label associated to input via [for] to #id
Alabels[1].textContent; // get the text of the 2nd label
// result: "I'm the 2nd label"
Here's a list of other properties used in the example below:
.checkValidity()
Event.target
.classList
The example has a step progression:
Pick a type
Pick a size
Choose how many layers
Step 2 is disabled until step 1 is completed.
Step 3 is disabled until the user enters valid data in step 2.
✻form controls: <button>, <fieldset>, <input>, <object>, <output>, <select>, <textarea>
const form = document.forms.cake;
form.onchange = cakeStep1;
form.addEventListener('input', cakeStep2);
function cakeStep1(e) {
const IO = this.elements;
const picked = e.target;
const radios = [...IO.type];
const l = IO.L;
const w = IO.W;
const d = IO.D;
const sSet = IO.sizeSet;
if (picked.name == 'type') {
radios.forEach(r => r.labels[0].classList.remove('active'));
picked.labels[0].classList.add('active')
sSet.disabled = false;
if (picked.id == 'sheet') {
d.disabled = true;
d.labels[0].classList.add('disabled');
l.disabled = false;
l.labels[0].classList.remove('disabled');
w.disabled = false;
w.labels[0].classList.remove('disabled');
} else {
d.disabled = false;
d.labels[0].classList.remove('disabled');
l.disabled = true;
l.labels[0].classList.add('disabled');
w.disabled = true;
w.labels[0].classList.add('disabled');
}
}
}
function cakeStep2(e) {
const IO = this.elements;
const origin = e.target;
const l = IO.L;
const w = IO.W;
const d = IO.D;
const lSet = IO.layerSet;
if (origin.name == 'size') {
if (IO.sheet.checked && l.checkValidity() == true && w.checkValidity() == true) {
lSet.disabled = false;
} else if (IO.round.checked && d.checkValidity() == true) {
lSet.disabled = false;
} else {
lSet.disabled = true;
}
}
}
html {
font: 2ch/1.2 'Segoe UI'
}
header {
margin-bottom: -12px;
padding: 0;
}
label {
display: block;
width: 18ch;
margin-bottom: 4px;
}
[type='radio'] {
display: inline-block;
vertical-align: baseline;
height: 1.5ex;
margin: 0;
}
[type='number'] {
display: :inline-block;
width: 10ch;
float: right;
text-align: center
}
.active {
font-weight: 900;
text-decoration: underline;
}
.disabled {
opacity: 0.4
}
<form id='cake'>
<header>
<h2>Cake Order</h2>
</header>
<fieldset name="typeSet">
<legend>Type</legend>
<label for='sheet'><input id="sheet" name="type" type="radio" value="sheet"> Sheet Cake</label>
<label for='round'><input id="round" name="type" value="round" type="radio"> Round Cake</label>
</fieldset>
<fieldset name="sizeSet" disabled>
<legend>Size (cm)</legend>
<label for='L' class='disabled'>Length: <input id="L" name='size' type="number" min="30" max="60" placeholder='30-60cm' required></label>
<label for='W' class='disabled'>Width: <input id="W" name='size' type="number" min="30" max="45" placeholder='30-45cm' required></label>
<label for='D' class='disabled'>Diameter: <input id="D" name='size' type="number" min="15" max="40" placeholder='15-40cm' required></label>
</fieldset>
<fieldset name="layerSet" disabled>
<legend>Layers</legend>
<select id='layers' name='layers'>
<option selected>Number of Layers</option>
<option value='1'>1 Layer</option>
<option value='2'>2 Layers</option>
<option value='3'>3 Layers</option>
</select>
</fieldset>
</form>
Related
I need to get the children of the Section block. Namely fields and rabiobuttons. Next, check them for fullness. How to do it. I tried to get through childNodes, children but nothing worked.
In this case, I want to get the context of the section block and check the fields
Such sections, I need to validate section by section and until the previous one is filled, I do not validate the next one.
const formStepTwo = document.getElementById("formStepTwo");
const Section = document.querySelectorAll(".Section");
formStepTwo.addEventListener("change", () => {
//console.log( Section.item(0))
let count = Array.from(Section).forEach((i) => {
let context = i.children;
context.item()
console.log( this.querySelectorAll(".input[type=radio]"))
//console.log(context.forEach());
});
});
<form class="stepTwo-profile" id="formStepTwo">
<p class="stepTwo-profile-title">Демография</p>
<div class="Section">
<label for="age"
>Возраст пациента<input
type="number"
class="stepTwo-profile-item-textAge"
name="age"
min="0"
max="80"
maxlength="2"
id="age"
/></label>
<p class="stepTwo-profile-item-smTitle">Пол</p>
<label for="male">
<input type="radio" name="gender" id="male" value="male" />Мужской
<span class="stepTwo-profile-item-radionbtn"></span
></label>
<label for="female">
<input type="radio" name="gender" id="female" value="female" />Женский
<span class="stepTwo-profile-item-radionbtn"></span>
</label>
</div>
</div>
</form>
You can actually check for input fields by targeting 'label' since they directly wrap over the input tag. Targeting through .Section can get a bit tricky, but is doable.
Another alternative is to directly target input fields using querySelectorAll('input') and then check for their type.
I've added example of both in the code snippet :
const formStepTwo = document.getElementById("formStepTwo");
const labels = document.querySelectorAll("label");
formStepTwo.addEventListener("change", () => {
let count = Array.from(labels).forEach((i) => {
let children = i.children;
Array.from(children).forEach((node) => {
if(node.nodeName.toLowerCase() === 'input') {
switch(node.type) {
case 'number' : validateNumberField(node);
break;
case 'radio' : validateRadio(node);
break;
// add more cases as required
default:
console.log('add default');
}
}
});
});
});
// Can also be done by targeting input directly
const input = document.querySelectorAll('input');
formStepTwo.addEventListener("change", () => {
Array.from(input).forEach((node) => {
if(node.nodeName.toLowerCase() === 'input') {
switch(node.type) {
case 'number' : validateNumberField(node);
break;
case 'radio' : validateRadio(node);
break;
// add more cases as required
default:
console.log('add default');
}
}
});
});
function validateNumberField(node) {
console.log('validating number field');
// add your validation
}
function validateRadio(node) {
console.log('validation radio button');
// add your validation for radio
}
<form class="stepTwo-profile" id="formStepTwo">
<p class="stepTwo-profile-title">Демография</p>
<div class="Section">
<label for="age"
>Возраст пациента<input
type="number"
class="stepTwo-profile-item-textAge"
name="age"
min="0"
max="80"
maxlength="2"
id="age"
/></label>
<p class="stepTwo-profile-item-smTitle">Пол</p>
<label for="male">
<input type="radio" name="gender" id="male" value="male" />Мужской
<span class="stepTwo-profile-item-radionbtn"></span
></label>
<label for="female">
<input type="radio" name="gender" id="female" value="female" />Женский
<span class="stepTwo-profile-item-radionbtn"></span>
</label>
</div>
</div>
</form>
Maybe this helps you:
const formStepTwo = document.getElementById("formStepTwo");
const sections = [...document.querySelectorAll(".Section")];
formStepTwo.addEventListener("input", () => {
sections.forEach(s=>{
const inps=[...s.querySelectorAll("input,select")].filter(el=>el.type!=="radio"||el.checked);
console.log(inps.map(el=>el.name+":"+el.value))
});
});
<form class="stepTwo-profile" id="formStepTwo">
<p class="stepTwo-profile-title">Демография</p>
<div class="Section">
<label for="age"
>Возраст пациента<input
type="number"
class="stepTwo-profile-item-textAge"
name="age"
min="0"
max="80"
maxlength="2"
id="age"
/></label>
<p class="stepTwo-profile-item-smTitle">Пол</p>
<label for="male">
<input type="radio" name="gender" id="male" value="male" />Мужской
<span class="stepTwo-profile-item-radionbtn"></span
></label>
<label for="female">
<input type="radio" name="gender" id="female" value="female" />Женский
<span class="stepTwo-profile-item-radionbtn"></span>
</label>
</div>
</form>
The script goes through all sections (currently there is only one ;-)) and collects all input values. (Radio buttons are only picked up if they are "checked".)
I am trying to get two divs to act as checkboxes (so that users can select 0 or all) that will influence hidden input values for a total that starts at 0. I am targetting the clicked divs by toggling a bootstrap color class to show user which has been chosen and - based on that class - add values to the hidden total input values below. I can get the totals to change outright, but I am trying to add to and subtract from the totals based on what is clicked/unclicked. Right now my code is returning an "Uncaught TypeError: Cannot set property 'value' of null". Any help you can give will be greatly appreciated!
$(document).ready(function() {
$('.select-class').on('click', function() {
//toggle clicked divs to show what's been selected
$(this).toggleClass('color');
//add values to total(0) if divs are clicked (have color class)
if (this.classList.contains('color')) {
//add1:
var addTotal1 = Number(document.getElementsByName('total1').value);
var addSingle1 = Number(document.getElementById(this.id.toString() + 'add1').value);
addTotal1 += addSingle1;
document.getElementById('totaladd1').value = addTotal1.toString();
//add2:
var addTotal2 = Number(document.getElementsByName('total2').value);
var addSingle2 = Number(document.getElementById(this.id.toString() + 'add2').value);
addTotal2 += addSingle2;
document.getElementById('totaladd2').value = addTotal2.toString();
//add3:
var addTotal3 = Number(document.getElementsByName('total3').value);
var addSingle3 = Number(document.getElementById(this.id.toString() + 'add3').value);
addTotal3 += addSingle3;
document.getElementById('totaladd3').value = addTotal3.toString();
}
//Subtract values if divs are unclicked (don't have color class)
if (!this.classList.contains('color')) {
//add1:
var addTotal1 = Number(document.getElementsByName('total1').value);
var addSingle1 = Number(document.getElementById(this.id.toString() + 'add1').value);
addTotal1 -= addSingle1;
document.getElementById('totaladd1').value = addTotal1.toString();
//add2:
var addTotal2 = Number(document.getElementsByName('total2').value);
var addSingle2 = Number(document.getElementById(this.id.toString() + 'add2').value);
addTotal2 -= addSingle2;
document.getElementById('totaladd2').value = addTotal2.toString();
//add3:
var addTotal3 = Number(document.getElementsByName('total3').value);
var addSingle3 = Number(document.getElementById(this.id.toString() + 'add3').value);
addTotal3 -= addSingle3;
document.getElementById('totaladd3').value = addTotal3.toString();
}
})
});
<div class="row p-lg-5">
<div id="div1" class="select-class">
<p>Content</p>
<!--hidden values-->
<div class="d-none">
<input type="number" class="add1" id="div1add1" value="1" />
<input type="number" class="add2" id="div1add2" value="45" />
<input type="number" class="add3" id="div1add3" value="4" />
</div>
</div>
<div id="div2" class="select-class">
<p>Content</p>
<!--hidden values-->
<div class="d-none">
<input type="number" class="add1" id="div2add1" value="3" />
<input type="number" class="add2" id="div2add2" value="20" />
<input type="number" class="add3" id="div2add3" value="3" />
</div>
</div>
</div>
<!--hidden totals-->
<div class="d-none">
<input id="totaladd1" type="number" name="total1" value="0" />
<input id="totaladd2" type="number" name="total2" value="0" />
<input id="totaladd3" type="number" name="total3" value="0" />
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Set your add inputs as disabled by default
Add a data-total="" to every total input. Inside the data place the add-inputs-pairs selector i.e: ".add_1" etc...
Toggle class on click and perform a search for the non disabled add inputs, reducing their values to an accumulated number. Set that number as the iterating total input value
jQuery(function($) {
function calculateTot() {
$('[data-total]').each(function() {
const pair = $(this.dataset.total).not(':disabled').get();
$(this).val(pair.reduce((n, el) => (n += +el.value, n), 0))
});
}
$('.select-class').on('click', function() {
$(this).toggleClass('is-selected');
$(this).find('input').prop('disabled', !$(this).is('.is-selected'));
calculateTot();
}).find('input').prop('disabled', true); // Make inputs disabled by default
calculateTot(); // Calculate also on DOM ready
});
.select-class {cursor:pointer; padding:8px; border-radius:1em; border:1px solid #000;}
.is-selected {background:#0bf;}
.d-none {display:none;}
<div class="row p-lg-5">
<div id="div1" class="select-class">
Content 1 - Select me
<div class="d-none">
<input type="number" class="add_1" value="1" />
<input type="number" class="add_2" value="45" />
<input type="number" class="add_3" value="4" />
</div>
</div>
<div id="div2" class="select-class">
Content 2 - Select me
<div class="d-none">
<input type="number" class="add_1" value="3" />
<input type="number" class="add_2" value="20" />
<input type="number" class="add_3" value="3" />
</div>
</div>
</div>
<div> <!-- class="d-none" -->
<input data-total=".add_1" type="number" name="total1" />
<input data-total=".add_2" type="number" name="total2" />
<input data-total=".add_3" type="number" name="total3" />
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I have a form in my HTML that takes in first name, last name, and phone number to create an account ID. The input textboxes for first name, last name, and account ID accept keyboard input and display it, as would be expected. However, when I'm viewing the page on the Firefox browser, only the phone number textbox doesn't work. I can click into the box once and see the cursor, but as soon as I start typing, no text shows up, and the cursor disappears. However, based on the Javascript creating an account ID with the last four digits of the phone number typed, I know the input is recognized. It works in other browsers, just not in Firefox.
<article>
<h2>New Account Information</h2>
<form>
<fieldset id="deliveryinfo">
<label for="fnameinputacct">First Name</label>
<input type="text" id="fnameinputacct" name="fname" />
<label for="lnameinputacct">Last Name</label>
<input type="text" id="lnameinputacct" name="lname" />
<label for="phoneinputacct">Phone Number</label>
<input type="text" id="phoneinputacct" name="phone" />
<label for="accountidbox">Account ID</label>
<input type="text" id="accountidbox" name="accountid" />
</fieldset>
<fieldset id="submitbutton">
<input type="submit" id="submitBtn" value="Create Account" />
</fieldset>
</form>
</article>
Here is the CSS
fieldset {
margin-bottom: 10px;
position: relative;
padding: 2.5em 1em 0.5em 1em;
background: #e3d5ba;
}
#deliveryinfo label {
display: block;
float: left;
clear: left;
margin-top: 5px;
}
#deliveryinfo input {
display: block;
margin-left: 130px;
}
#fnameinputacct, #lnameinputacct, #phoneinputacct, #accountidbox {
width: 12em;
}
#submitBtn {
font-size: 1.25em;
}
And some Javascript that goes with the fields. This method is added in another function.
function createID() {
var fname = document.getElementById("fnameinputacct");
var lname = document.getElementById("lnameinputacct");
var phone = document.getElementById("phoneinputacct");
var account = document.getElementById("accountidbox");
var fields = document.getElementsByTagName("input");
var acctid;
var fistInit;
var lastInit;
if (fname != "" && lname != "" && phone != "") {
fistInit = fname.value.charAt(0).toUpperCase();
lastInit = lname.value.charAt(0).toUpperCase();
acctid = fistInit + lastInit + phone.value.substring(phone.value.length - 4);
account.value = acctid;
newAccountArray = [];
for (var i = 0; i < fields.length - 1; i++) {
newAccountArray.push(fields[i].value);
}
}
}
You might try breaking up your form field groups with a <div> or <p>.
See https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/How_to_structure_an_HTML_form
Some of the widely used css frameworks do this as well. Look at Semantic UI, Bootstrap, or Material. These do a similar grouping with div containers for each label/input
Example from semantic ui form:
<form class="ui form">
<div class="field">
<label>First Name</label>
<input type="text" name="first-name" placeholder="First Name">
</div>
<div class="field">
<label>Last Name</label>
<input type="text" name="last-name" placeholder="Last Name">
</div>
<div class="field">
<div class="ui checkbox">
<input type="checkbox" tabindex="0" class="hidden">
<label>I agree to the Terms and Conditions</label>
</div>
</div>
<button class="ui button" type="submit">Submit</button>
</form>
I've got a function which breaks ALL other javascript / jquery on the page.
What I'm trying to do with the function below is duplicate a div upon button press and append it after the initial one (can be duplicated as many times as pressed) - and it works great, except everything else breaks.
I've added the snippets above it just for reference, but it's the actual function duplicateContact() which is causing the issues.
If someone could help with pointing out my mistake I'd love to be able to use the function without having it kill everything else.
//add more contacts
document.getElementById('C_addContact').onclick = duplicateContact;
var i = 0;
var original = document.getElementById('C_contacts');
var nextElement = $.extend(original);
function duplicateContact()
{
var clone = original.cloneNode(true); // "deep" clone
clone.id = "C_contacts" + ++i; // there can only be one element with an ID
nextElement.parentNode.insertBefore(clone, nextElement.nextSibling);
}
Below is my remaining js:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="text/javascript">
//show hidden div upon select box selection
$(function() {
$('#otherTitleField').hide();
$('#title').change(function(){
if($('#title').val() == 'Other') {
$('#otherTitleField').show();
} else {
$('#otherTitleField').hide();
}
});
});
//show hidden div upon radio button selection
$(document).ready(function() {
$('input[type="radio"]').click(function() {
if($(this).attr('id') == 'postno') {
$('#postalnofield').show();
}
else {
$('#postalnofield').hide();
}
});
});
//show different hidden div based on checkboxes
function valueChanged1()
{
if($('#tfn').is(":checked")) {
$("#tfnfield").show();
}
else
$("#tfnfield").hide();
}
function valueChanged2()
{
if($('#abn').is(":checked")) {
$("#abnfield").show();
}
else
$("#abnfield").hide();
}
//clear contacts div
function clearBox(elementID)
{
if(elementID != 'C_contacts') {
document.getElementById(elementID).innerHTML = "";
}
}
</script>
And the HTML for the div which is being cloned:
<div id="C_contacts">
<p><label for="C_familyName">Family name<span class="mandatory">*</span></label>
<input type="text" id="C_familyName" name="Section C Family Name" required></p>
<p><span style="display:inline-block; width:49%;">
<label for="C_givenName">First given name<span class="mandatory">*</span></label>
<input type="text" id="C_givenName" name="Section C Given Name" required></span>
<span style="display:inline-block; width:49%;">
<label for="C_otherName">Other given name/s<span class="mandatory">*</span></label>
<input type="text" id="C_otherName" name="Section C Other Names" required>
</span></p>
<p><label for="C_position">Position held<span class="mandatory">*</span></label>
<input type="text" id="C_position" name="Section C Position Held" required></p>
<p><span style="display:inline-block; width:49%;">
<label for="C_busPhone">Business phone<span class="mandatory">*</span></label>
<input type="tel" id="C_busPhone" name="Section C Business Phone" required>
</span>
<span style="display:inline-block; width:49%;">
<label for="C_mobPhone">Mobile phone</label>
<input type="tel" id="C_mobPhone" name="Section C Mobile">
</span></p>
<p><label for="C_busEmail">Business email address</label>
<input type="email" id="C_busEmail" name="Section C Email"></p>
<p><label for="C_thisApp C_busOp">This person is the authorised contact for information about:<span class="mandatory">*</span></label><br>
<input type="checkbox" id="C_thisApp" name="This Application" value="thisApp"> this application<br>
<input type="checkbox" id="C_busOp" name="Operation of Business" value="busOp"> the operation of the business after we have granted a licence</p>
<p><input type="button" id="C_removeContact" value="Remove contact" onclick="clearBox(this.parentNode.parentNode.id)"></p>
<p><input type="button" id="C_addContact" onclick="duplicateContact()" value="Add more contacts"></p>
<hr>
</div>
UPDATE: Apparently I had two versions of jquery which was causing issues. I have no idea how I missed this - thank you to everyone for the suggestions and help, this is resolved.
I don't know what is your actual code, but I can see every time you are cloning a div in which you are cloning remove and add buttons. But you need to create a single Add button for cloning and there are remove buttons for all clone divs. Also your function clearBox is not called for the newly generated divs, to make it work you can use jQuery.on() and use toggle() to show hide so that your code can be short. Below is the working snippet which can help you for your functionality
//add more contacts
document.getElementById('C_addContact').onclick = duplicateContact;
var i = 0;
var original = document.getElementById('C_contacts');
var nextElement = $.extend(original);
function duplicateContact() {
var clone = original.cloneNode(true); // "deep" clone
clone.id = "C_contacts" + ++i; // there can only be one element with an ID
nextElement.parentNode.insertBefore(clone, nextElement.nextSibling);
}
//show hidden div upon select box selection
$(function() {
$('#otherTitleField').hide();
$('#title').change(function() {
$('#otherTitleField').toggle(this.value == 'Other');
});
//show hidden div upon radio button selection
$('input[type="radio"]').click(function() {
$('#postalnofield').toggle(this.id == 'postno');
});
// using event delegation with document for removing dynamic divs
$(document).on('click', '.remove-contacts', function() {
$(this).closest('.c-contacts').attr('id') !== 'C_contacts' &&
$(this).closest('.c-contacts').remove();
});
});
//show different hidden div based on checkboxes
function valueChanged1() {
$("#tfnfield").toggle($('#tfn').is(":checked"));
}
function valueChanged2() {
$("#abnfield").toggle($('#abn').is(":checked"));
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="C_contacts" class="c-contacts">
<p>
<label for="C_familyName">Family name<span class="mandatory">*</span></label>
<input type="text" id="C_familyName" name="Section C Family Name" required>
</p>
<p><span style="display:inline-block; width:49%;">
<label for="C_givenName">First given name<span class="mandatory">*</span></label>
<input type="text" id="C_givenName" name="Section C Given Name" required>
</span>
<span style="display:inline-block; width:49%;">
<label for="C_otherName">Other given name/s<span class="mandatory">*</span></label>
<input type="text" id="C_otherName" name="Section C Other Names" required>
</span>
</p>
<p>
<label for="C_position">Position held<span class="mandatory">*</span></label>
<input type="text" id="C_position" name="Section C Position Held" required>
</p>
<p><span style="display:inline-block; width:49%;">
<label for="C_busPhone">Business phone<span class="mandatory">*</span></label>
<input type="tel" id="C_busPhone" name="Section C Business Phone" required>
</span>
<span style="display:inline-block; width:49%;">
<label for="C_mobPhone">Mobile phone</label>
<input type="tel" id="C_mobPhone" name="Section C Mobile">
</span></p>
<p>
<label for="C_busEmail">Business email address</label>
<input type="email" id="C_busEmail" name="Section C Email">
</p>
<p>
<label for="C_thisApp C_busOp">This person is the authorised contact for information about:<span class="mandatory">*</span></label>
<br>
<input type="checkbox" id="C_thisApp" name="This Application" value="thisApp"> this application
<br>
<input type="checkbox" id="C_busOp" name="Operation of Business" value="busOp"> the operation of the business after we have granted a licence</p>
<p>
<input type="button" id="C_removeContact" value="Remove contact" class="remove-contacts">
</p>
<hr>
</div>
<p>
<input type="button" id="C_addContact" value="Add more contacts">
</p>
I'm building a huge form that requires me to initially show the opacity of elements at 0.5 and when a button is clicked the opacity is 1.0. I am able to do this with JavaScript but I need to manage it better by not calling an if statement for each element. Note that the elements are in no particular order and some need to toggle the opacity of more than one element.
Working Demo need to revise
SIMPLE CSS
[id^="dp"] {
opacity: 0.5;
}
HTML
GROUP 1<BR>
<input type="radio" id="abc1" name="abc1" onclick="showabc();"/>
<label for="abc1"> Yes </label>
<input type="radio" id="abc2" name="abc1" onclick="showabc();"/>
<label for="abc2"> No </label>
<div id="dpabc1">
<H4>Content 1 is dimmed</H4>
</div>
GROUP 2<BR>
<input type="radio" id="abc3" name="abc2" onclick="showabc();"/>
<label for="abc3"> Yes </label>
<input type="radio" id="abc4" name="abc2" onclick="showabc();"/>
<label for="abc4"> No </label>
<div id="dpabc7">
<H4>Content 2 is dimmed</H4>
</div>
GROUP 3<BR>
<input type="radio" id="abc5" name="abc3" onclick="showabc();"/>
<label for="abc5"> Yes </label>
<input type="radio" id="abc6" name="abc3" onclick="showabc();"/>
<label for="abc6"> No </label>
<div id="dpabc9">
<H4>Content 3 item 1 in its own div</H4>
</div>
<div id="dpabc11">
<H4>Content 3 item2 in its own div</H4>
CURRENT JAVASCRIPT I NEED TO REWRITE WITHOUT A BUNCH OF IF STATEMENTS FOR EACH ELEMENT
function showabc() {
if (document.getElementById("abc1").checked == true) {
document.getElementById("dpabc1").style.opacity = 1.0;
}
else {
document.getElementById("dpabc1").style.opacity = 0.5;
}
if (document.getElementById("abc3").checked == true) {
document.getElementById("dpabc7").style.opacity = 1.0;
}
else {
document.getElementById("dpabc7").style.opacity = 0.5;
}
if (document.getElementById("abc5").checked == true) {
document.getElementById("dpabc9").style.opacity = 1.0;
document.getElementById("dpabc11").style.opacity = 1.0;
}
else {
document.getElementById("dpabc9").style.opacity = 0.5;
document.getElementById("dpabc11").style.opacity = 0.5;
}
}
BEGINNING OF CODE REVISION HERE'S WHERE I'M STUCK. What I'm trying to do is match the variables in "checkMe" with the variables in dimMe. You can see abc1 & 3 need to show the opacity change of one item where abc5 needs to change to opacity to two items (dpabc9 & dpabc11).
function showabc() {
var checkMe = ["abc1" , "abc3" , "abc5" ];
var dimMe = ["dpabc1" , "dpabc7" , "dpabc9, dpabc11"];
for (var i=0, l=checkMe.length; i<l; ++i) {
document.getElementById(checkMe[i]).style.opacity = 1.0;
}
else {
document.getElementById(checkMe[i]).style.opacity = 0.5;
}
}
Given some minor changes to the HTML, the appropriate grouping of elements within <fieldset> elements, and the use of yes/no values, I'd suggest the following JavaScript:
function opacityToggle(){
// 'this' refers to the element to which the event-handling was bound:
var divs = this.getElementsByTagName('div'),
// using CSS syntax offered by 'querySelector()' to find the
// first input element of 'type=radio' and is checked:
confirmed = this.querySelector('input[type="radio"]:checked');
// iterates over the 'div' elements, and sets the opacity according
// to whether the checked radio input has the value of 'yes':
for (var i = 0, len = divs.length; i < len; i++) {
divs[i].style.opacity = confirmed.value === 'yes' ? 1 : 0.5;
}
}
// gets the fieldset elements:
var fieldsets = document.getElementsByTagName('fieldset');
// iterates over the fieldset elements:
for (var i = 0, len = fieldsets.length; i < len; i++) {
// and uses 'addEventListener' to add a listener for the 'change' event,
// when that event is detected, the opacityToggle function is called:
fieldsets[i].addEventListener('change', opacityToggle);
}
JS Fiddle demo.
This works on the following HTML:
<fieldset>
<legend>GROUP 1</legend>
<input type="radio" id="abc1" name="abc1" value="yes" />
<label for="abc1">Yes</label>
<input type="radio" id="abc2" name="abc1" value="no" />
<label for="abc2">No</label>
<div id="dpabc1">
<H4>Content 1 is dimmed</H4>
</div>
</fieldset>
<fieldset>
<legend>GROUP 2</legend>
<input type="radio" id="abc3" name="abc2" value="yes" />
<label for="abc3"> Yes </label>
<input type="radio" id="abc4" name="abc2" value="no" />
<label for="abc4"> No </label>
<div id="dpabc7">
<H4>Content 2 is dimmed</H4>
</div>
</fieldset>
<fieldset>
<legend>GROUP 3</legend>
<input type="radio" id="abc5" name="abc3" value="yes" />
<label for="abc5"> Yes </label>
<input type="radio" id="abc6" name="abc3" value="no" />
<label for="abc6"> No </label>
<div id="dpabc9">
<H4>Content 3 item 1 in its own div</H4>
</div>
<div id="dpabc11">
<H4>Content 3 item2 in its own div</H4>
</div>
</fieldset>
UPDATED HTML
UPDATED FIDDLE
GROUP 1<BR>
<input type="radio" id="abc1" name="abc1" onclick="showabc('content1',1);"/>
<label for="abc1"> Yes </label>
<input type="radio" id="abc2" name="abc1"
onclick="showabc('content1',0);"/>
<label for="abc2"> No </label>
<div id="dpabc1" class="content1">
<H4>Content 1 is dimmed</H4>
</div>
GROUP 2<BR>
<input type="radio" id="abc3" name="abc2" onclick="showabc('content2',1);"/>
<label for="abc3"> Yes </label>
<input type="radio" id="abc4" name="abc2" onclick="showabc('content2',0);"/>
<label for="abc4"> No </label>
<div id="dpabc7" class="content2">
<H4>Content 2 is dimmed</H4>
</div>
GROUP 3<BR>
<input type="radio" id="abc5" name="abc3" onclick="showabc('content3',1);"/>
<label for="abc5"> Yes </label>
<input type="radio" id="abc6" name="abc3" onclick="showabc('content3',0);"/>
<label for="abc6"> No </label>
<div id="dpabc9" class="content3">
<H4>Content 3 item 1 in its own div</H4>
</div>
<div id="dpabc11" class="content3">
<H4>Content 3 item2 in its own div</H4>
</div>
UPDATED JAVASCRIPT
function showabc(cssClass,makeBold) {
var elements = document.getElementsByClassName(cssClass);
var opacity = 1.0;
if (makeBold == 0) {
opacity = 0.5;
}
for (var i = 0; i < elements.length; i++) {
elements[i].style.opacity = opacity;
}
}