This is my first time using Javascript, so please forgive me. I'm still not solid on the terminology or best practices, but I'm losing my mind with how complex this script is getting for such a simple thing.
Also if there's a better way, in general, to do what I'm trying to do, let me know because boy I have lost sleep on this one.
Context:
I have a form to build standardized email signatures. The user puts their info into the inputs and then copies the output from a copyable area with standardized styling specific for email markup. In each signature, someone may include the information for another person in their company.
I have a set of radio buttons that enable 0, 1, 2, or 3 additional fieldsets of input for these team members. In addition to adding fieldsets of inputs, they also enable outputs in the copyable area. The outputs have to be "display: none" so that someone who does not include this information in their signature doesn't end up with blank table cells in their copied signature.
https://jsfiddle.net/slingtruchoice/jrem21yb/
Here's the whole, ugly thing. I'm proud but also so not proud of it. Like I said, literally the first time I've ever used javascript. Specifically, I'm looking at this:
var radios = document.getElementsByName('addTeam');
for (var i = 0; i < radios.length; i++) {
radios[i].addEventListener('change', function() {
//--------------------------------- || RADIO BUTTONS || -------------------------------------------
let fieldset = document.getElementsByClassName('sigform-fieldset'), //CLASS fieldset for all radio buttons
inputs = document.getElementsByClassName('sigform-team'), //CLASS all radio buttons
izero = document.getElementById('add-team__0'), //ID radio button, input 0
ione = document.getElementById('add-team__1'), //ID radio button, input 1
itwo = document.getElementById('add-team__2'), //ID radio button, input 2
ithree = document.getElementById('add-team__3'); //ID radio button, input 3
//--------------------------------- || INPUT SECTIONS || -------------------------------------------
let divs = document.getElementsByClassName('sigform__team-inputs'), //CLASS all input wrapper divs
done = document.getElementById('team-inputs__1'), //ID div of input section, team 1
dtwo = document.getElementById('team-inputs__2'), //ID div of input section, team 2
dthree = document.getElementById('team-inputs__3'); //ID div of input section, team 3
//--------------------------------- || SIGNATURE OUTPUT || -------------------------------------------
let // ------------------------ Table Rows -------------------------------------------
teamsrows = document.getElementsByClassName('extraTeamWrap'), //CLASS of tr wrap each output table
teamwrap1 = document.getElementById('extraTeamWrap1'), //ID tr wrap of output table team 1
teamwrap2 = document.getElementById('extraTeamWrap2'), //ID tr wrap of output table team 2
teamwrap3 = document.getElementById('extraTeamWrap3'), //ID tr wrap of output table team 3
// ------------------------ Tables -------------------------------------------
teamtables = document.getElementsByClassName('extraTeamTable'), //CLASS of table for each output
teamtable1 = document.getElementById('extraTeamTable-one'), // ID table wrap of output table team 1
teamtable2 = document.getElementById('extraTeamTable-two'), // ID table wrap of output table team 2
teamtable3 = document.getElementById('extraTeamTable-three'); // ID table wrap of output table team 3
if (ione.checked == false && itwo.checked == false && ithree.checked == false || izero.checked == true){
done.style.display = 'none';
dtwo.style.display = 'none';
dthree.style.display = 'none';
teamsrows.style.display = 'none';
} else if (ione.checked == true && itwo.checked == false && ithree.checked == false) {
done.style.display = 'block';
teamsrows.style.display = "block";
dtwo.style.display = 'none';
dthree.style.display = 'none';
} else if (ione.checked == false && itwo.checked == true && ithree.checked == false) {
done.style.display = 'block';
dtwo.style.display = 'block';
dthree.style.display = 'none';
} else if (ione.checked == false && itwo.checked == false && ithree.checked == true) {
done.style.display = 'block';
dtwo.style.display = 'block';
dthree.style.display = 'block';
} else {
return false;
}
});
}
And it's not even done. (Oh yeah, by the way, please don't expect this fiddle to work. It's far from there.)
How do I go about this better? I'm having difficulty googling answers for my questions since I don't really know how to say "how to make an argument equal to multiple IDs that are paired specifically with other IDs to do something to that ID when the other ID is activated... +javascript" in a way that yields useful results.
My only request is that any explanation come in very simple language. I really can't iterate enough how much of an absolute beginner I am. Most responses on StackExchange I've found for other questions have just blown right over my head.
And really, thank you for any help you're able to give!
Well, that took more than a minute. Here is the updated code. Are there more efficient ways of doing this? Probably. Here, I want you take away how data structures can simplify your code.
let radios = document.getElementsByName('addTeam');
for (let i = 0; i < radios.length; i++) {
radios[i].addEventListener('change', function() {
//Based on whether it is a class or an id
const elementClasses = [
'sigform-fieldset',
'sigform-team',
'sigform__team-inputs',
'extraTeamWrap',
'extraTeamTable',
];
const elementIds = [
'add-team__0',
'add-team__1',
'add-team__2',
'add-team__3',
'team-inputs__1',
'team-inputs__2',
'team-inputs__3',
'extraTeamWrap1',
'extraTeamWrap2',
'extraTeamWrap3',
'extraTeamTable-one',
'extraTeamTable-two',
'extraTeamTable-three'
];
//Adding elements to the loop
elementsTotal = [];
//For each loop to iterate the array
elementClasses.forEach(element => {
push(document.getElementsByClassName(element));
});
elementIds.forEach(element => {
push(document.getElementsByClassName(element));
});
//The commented code is for classes.
//document.getElementsByClassName returns a collection, so you must iterate that collection to style.
if (elementsTotal[6].checked == false && elementsTotal[7].checked == false && elementsTotal[8].checked == false || elementsTotal[5].checked == true){
elementsTotal[9].style.display = 'none';
elementsTotal[10].style.display = 'none';
elementsTotal[11].style.display = 'none';
//teamsrows.style.display = 'none';
} else if (elementsTotal[6].checked == true) {
elementsTotal[9].style.display = 'block';
//teamsrows.style.display = "block";
elementsTotal[10].style.display = 'none';
elementsTotal[11].style.display = 'none';
} else if (elementsTotal[7].checked == true) {
elementsTotal[9].style.display = 'block';
elementsTotal[10].style.display = 'block';
elementsTotal[11].style.display = 'none';
} else if (elementsTotal[8].checked == true) {
elementsTotal[9].style.display = 'block';
elementsTotal[10].style.display = 'block';
elementsTotal[11].style.display = 'block';
} else {
return false;
}
});
}
So I talked about objects, but I can't really see how it might be implemented here. Thus, I would like to show an example of how it might be used.
Example from: https://betterprogramming.pub/stop-putting-so-many-if-statements-in-your-javascript-3b65aaa4b86b
Here, is a pretty simple if statement approach, not the most clean code.
function getStatusColor (status) {
if (status === 'success') {
return 'green'
}
if (status === 'warning') {
return 'yellow'
}
if (status === 'info') {
return 'blue'
}
if (status === 'error') {
return 'red'
}
}
Better code:
function getStatusColor (status) {
return {
success: 'green',
warning: 'yellow',
info: 'blue',
error: 'red'
}[status]
}
With an object, it is easier to tell what is happening. I couldn't fit an object anywhere in your code as the if statements had booleans instead of strings. (I merely thought about strings, I wish I knew how to do it with booleans, though!)
Again, use data structures! I hope you learned some things, I did too.
Pretty impressive starter project and results! I am also learning Javascript and the most important thing for me are speaking and short variable/function names. If you can still understand it after 3 or 6 months, it's good code :)
Maybe an unexpected answer, but at least from my perspective some repetition is OK. Especially, for this "smaller" project and because you just started coding in Javascript. You can still tweak your code and remove repetitions later.
The "refactored" code still cannot write to the extra fields to the right but now it:
adds the extra fields (at the bottom and to the right) depending on your team checkboxes.
uses shorter and more speaking variable names, incl. all HTML elements (repeating the word "sigform" may be unnecessary).
For a loop to add an eventlistener to all checkboxes, check out:
Attach listener to multiple children
Regarding the code repetition, check out:
JavaScript: Dynamically Creating Variables for Loops
Let me know if you have any questions or issues to understand my changes. I hope this helps.
const phonePrinter = function() {
// using more speaking names here, can still be improved
let phoneNumberDir = document.querySelector('#input__phone__dir').value.replace(/\D/g, "");
let directPhone = document.querySelector('#phone-output__dir');
let officePhone = document.querySelector('#input__phone__off').value.replace(/\D/g, "");
let extension = document.querySelector('#input__ext__off').value;
let officePhoneWithExtension = officePhone + ',' + extension;
let phoneLinkOff = document.querySelector('#phone-output__off');
// the input is a phone number
function validatePhoneNumber(phoneNumber) {
var re = /^\(?(\d{3})\)?[- ]?[. ]?(\d{3})[- ]?[. ]?(\d{4})$/;
return re.test(phoneNumber);
return phoneNumber
}
// let's use only if statemetns for clarity, you return directly anyway
const noPhoneNumber = officePhone == '' && phoneNumberDir == ''
if (noPhoneNumber) {
alert("Enter at least one phone number.")
return
}
if (!validatePhoneNumber(officePhone)) {
alert("Enter a valid office phone number.")
return
}
if (!validatePhoneNumber(phoneNumberDir)) {
alert("Enter a valid direct phone number.")
return
}
//populating the phone in the href
directPhone.setAttribute("href", "tel:" + phoneNumberDir);
directPhone.innerHTML = addDots(phoneNumberDir);
//populating the phone + ext in the href
phoneLinkOff.setAttribute("href", "tel:" + officePhoneWithExtension);
phoneLinkOff.innerHTML = addDots(phoneNumberDir, extension);
event.preventDefault();
};
// function to handle the dots in the phone number, externalNumber is a default parameter, not set by default
function addDots(phoneNumber, externalNumber='') {
var number = phoneNumber.slice(0, 3) + "." + phoneNumber.slice(3, 6) + "." + phoneNumber.slice(6, 10);
// if external number is set, add it to the number output
if (externalNumber != '') { return number + " ext " + externalNumber }
return number
}
// this should be much clearer now. New order and shorter names
function printName() {
var name = document.querySelector('#input__name').value;
var title = document.querySelector('#input__title').value;
if (name == '') alert("Please enter your name.");
if (title == '') alert('Please enter your title.');
if (name != '' && title != '') {
const nameOutput = document.querySelector('#nameOutput');
const titleOutput = document.querySelector('#titleOutput');
nameOutput.innerHTML = name;
titleOutput.innerHTML = title;
}
}
// removed the uncommented code here, just for testing
// checkLimiter = document.getElementsByTagName('banner-checks'); ...
var checkbox = document.querySelectorAll(".check");
for (var i = 0; i < checkbox.length; i++)
checkbox[i].onclick = selectiveCheck;
function selectiveCheck(event) {
var checked = document.querySelectorAll(".check:checked");
// only used here, updated the name and use > maxBanners below instead of = and +1
const maxBanners = 2
if (checked.length > maxBanners) {
alert("You may only have up to two additional banners in your signature.");
return false;
}
}
// not required to set default hidden in your html
// the classList.add("hidden") will hide the elements
// below, we will remove the hidden class using remove to make it visible again
var teamFields1 = document.getElementById('team-inputs__1');
var teamFields2 = document.getElementById('team-inputs__2');
var teamFields3 = document.getElementById('team-inputs__3');
teamFields1.classList.add("hidden");
teamFields2.classList.add("hidden");
teamFields3.classList.add("hidden");
// name maybe still not optimal
var table1 = document.getElementById('teamTable1');
var table2 = document.getElementById('teamTable2');
var table3 = document.getElementById('teamTable3');
table1.classList.add("hidden");
table2.classList.add("hidden");
table3.classList.add("hidden");
// unsure how to handle/improve this right now, see link in answer
var radios = document.getElementsByName('addTeam');
for (let i = 0; i < radios.length; i++) {
radios[i].addEventListener('click', function() {
// removed some variables, we still have repetition
const input0 = document.getElementById('add-team__0');
const input1 = document.getElementById('add-team__1');
const input2 = document.getElementById('add-team__2');
const input3 = document.getElementById('add-team__3');
if (input0.checked == true){
table1.classList.add('hidden');
table2.classList.add('hidden');
table3.classList.add('hidden');
teamFields1.classList.add("hidden");
teamFields2.classList.add("hidden");
teamFields3.classList.add("hidden");
} else if (input1.checked == true) {
table1.classList.remove('hidden');
table2.classList.add('hidden');
table3.classList.add('hidden');
teamFields1.classList.remove("hidden");
teamFields2.classList.add("hidden");
teamFields3.classList.add("hidden");
} else if (input2.checked == true) {
table1.classList.remove('hidden');
table2.classList.remove('hidden');
table3.classList.add('hidden');
teamFields1.classList.remove("hidden");
teamFields2.classList.remove("hidden");
teamFields3.classList.add("hidden");
} else if (input3.checked == true) {
table1.classList.remove('hidden');
table2.classList.remove('hidden');
table3.classList.remove('hidden');
teamFields1.classList.remove("hidden");
teamFields2.classList.remove("hidden");
teamFields3.classList.remove("hidden");
}
});
}
function populate() {
phonePrinter();
printName();
}
#import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght#400;600&display=swap');
body {
font-size: 16;
font-family: "Source Sans Pro", Arial, sans-serif;
margin: 0;
padding: 0;
box-sizing: border-box;
background-color: #095285;
}
.columns {
display: flex;
flex-direction: row;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0.4) 100%);
}
form {
padding: 5vw;
width: 40vw;
margin: 30px auto;
display: flex;
flex-direction: column;
}
.input {
display: block;
padding: 10px 10px 5px 0;
width: 100%;
box-sizing: border-box;
margin: 10px;
background-color: transparent;
border-top: none;
border-left: none;
border-right: none;
border-bottom: 2px solid #095285;
font-size: 24px;
font-weight: 600;
font-family: "Source Sans Pro", Arial, sans-serif;
color: #095285;
}
.input::placeholder {
font-weight: 400;
font-size: 24px;
color: #095285;
font-family: "Source Sans Pro", Arial, sans-serif;
opacity: 1;
text-transform: uppercase;
}
.output {
width: 40vw;
padding: 5vw;
margin: 30px auto;
display: flex;
flex-direction: column;
justify-content: center;
}
.output > .table-wrapper {
font-family: "Source Sans Pro", sans-serif;
color: #095285;
font-size: 16px;
background-color: white;
border: 2px solid #095285;
padding: 2vw;
min-width: 375px;
}
.instructions {
font-size: 24px;
font-weight: bolder;
text-align: center;
color: #095285;
}
.no-select::selection {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: no-drop;
}
.selectable::selection,
table.selectable>*::selection {
-webkit-touch-callout: auto;
-webkit-user-select: auto;
-khtml-user-select: auto;
-moz-user-select: auto;
-ms-user-select: auto;
user-select: auto;
cursor: copy !important;
}
/* banners, checkboxes */
/* checkboxes */
.dropdown-hidden {
display: none;
}
.dropdown-visible {
display: block;
}
/* banners */
.banner-hidden {
display: none;
}
.banner-visible {
display: block;
}
.visible {
display: block;
}
.hidden {
display: none;
}
<div class="columns">
<!-- the only place where I kept sigform in the name. Other refs have been removed for shorter names -->
<form class="sigform" id="sigform" name="sigform">
<input class="input" id="input__name" type="text" placeholder="Name:">
<input class="input" id="input__title" type="text" placeholder="Title:">
<input class="input" id="input__phone__dir" type="tel" placeholder="Direct phone number:">
<input class="input" id="input__phone__off" type="tel" placeholder="Office phone number:">
<input class="input" id="input__ext__off" type="number" placeholder="Office Extension:">
<input class="input" id="input__website" type="url" placeholder="Team Website:">
<label class="label" id="label__banner-inst" for="field__banner-fs">Add banners to your signature. You may choose up to 2.
<fieldset class="fieldset" id="field__banner-fs" labeledby="label__banner-inst">
<label class="label" id="label__banner-one">
<input class="check" type="checkbox" name="banner-checks">
</label>
<label class="label" id="label__banner-two">
<input class="check" type="checkbox" name="banner-checks">
</label>
<label class="label" id="label__banner-three">
<input class="check" type="checkbox" name="banner-checks">
</label>
<label class="label" id="label__banner-four">
<input class="check" type="checkbox" name="banner-checks">
</label>
<label class="label" id="label__banner-five">
<input class="check" type="checkbox" name="banner-checks">
</label>
<label class="label" id="label__banner-six">
<input class="check" type="checkbox" name="banner-checks">
</label>
</fieldset>
</label>
<label class="label" id="label__add-team">How many additional team members would you like represented in your signature?</label>
<fieldset class="fieldset" id="field__add-team" labeledby="label__add-team">
<label class="label" id="label__add-team__0" for="add-team__0">0
<input class="team" id="add-team__0" type="radio" name="addTeam" value="0" labeledby="label__add-team__0" checked>
</label>
<label class="label" id="label__add-team__1" for="add-team__1">1
<input class="team" id="add-team__1" type="radio" name="addTeam" value="1" labeledby="label__add-team__1">
</label>
<label class="label" id="label__add-team__2" for="add-team__2">2
<input class="team" id="add-team__2" type="radio" name="addTeam" value="2" labeledby="label__add-team__2">
</label>
<label class="label" id="label__add-team__3" for="add-team__3">3
<input class="team" id="add-team__3" type="radio" name="addTeam" value="3" labeledby="label__add-team__3">
</label>
</fieldset>
<fieldset class="fieldset" id="field__team-sigs">
<div class="team-inputs" id="team-inputs__1">
<input type="text" id="team-1__name" class="input" placeholder="Team Member Name:">
<input type="text" id="team-1__title" class="input" placeholder="Title:">
<input type="text" id="team-1__email" class="input" placeholder="Email:">
<input type="text" id="team-1__phone" class="input" placeholder="Direct Phone Number:">
</div>
<div class="team-inputs hidden" id="team-inputs__2">
<input type="text" id="team-2__name" class="input" placeholder="Team Member Name:">
<input type="text" id="team-2__title" class="input" placeholder="Title:">
<input type="text" id="team-2__email" class="input" placeholder="Email:">
<input type="text" id="team-2__phone" class="input" placeholder="Direct Phone Number:">
</div>
<div class="team-inputs start-hidden" id="team-inputs__3">
<input type="text" id="team-3__name" class="input" placeholder="Team Member Name:">
<input type="text" id="team-3__title" class="input" placeholder="Title:">
<input type="text" id="team-3__email" class="input" placeholder="Email:">
<input type="text" id="team-3__phone" class="input" placeholder="Direct Phone Number:">
</div>
</fieldset>
<button id="submit" type="button" onClick="populate()">Submit</button>
<img src="">
</form>
<div class="output">
<p class="instructions no-select">
HIGHLIGHT EVERYTHING BELOW TO COPY AND PASTE IN YOUR SIGNATURE
</p>
<div class="table-wrapper">
<table class="signature selectable">
<tr>
<td colspan="1" id="nameOutput">Bobby Joe</td>
</tr>
<tr>
<td colspan="1" id="titleOutput">Web Developer | Graphic Designer</td>
</tr>
<tr>
<td colspan="1"><span id="phoneWrapper">Direct: 111.222.3333 | Office: 111.222.3333 ext. 123</span></td>
</tr>
<tr>
<td colspan="1"><img src="https://via.placeholder.com/350x65">
</td>
</tr>
<tr class="extraTeamWrap" id="extraTeamWrap1">
<table class="extraTeamTable" id="teamTable1">
<tr>
<td class="extraTeam teamName" id="team-name__one">Extra Team member</td>
</tr>
<tr>
<td class="extraTeam teamTitle" id="team-title__one">Extra Team title</td>
</tr>
<tr>
<td class="extraTeam teamEmail" id="team-email__one">Extra Team email</td>
</tr>
<tr>
<td class="extraTeam teamPhone" id="team-phone__one">111.222.6666</td>
</tr>
</table>
</tr>
<tr class="extraTeamWrap" id="extraTeamWrap2">
<table class="extraTeamTable" id="teamTable2">
<tr>
<td class="extraTeam teamName" id="team-name__two">Extra Team member</td>
</tr>
<tr>
<td class="extraTeam teamTitle" id="team-title__two">Extra Team title</td>
</tr>
<tr>
<td class="extraTeam teamEmail" id="team-email__two">Extra Team email</td>
</tr>
<tr>
<td class="extraTeam teamPhone" id="team-phone__two">111.222.6666</td>
</tr>
</table>
</tr>
<tr class="extraTeamWrap" id="extraTeamWrap3">
<table class="extraTeamTable" id="teamTable3">
<tr>
<td class="extraTeam teamName" id="team-name__three">Extra Team member</td>
</tr>
<tr>
<td class="extraTeam teamTitle" id="team-title__three">Extra Team title</td>
</tr>
<tr>
<td class="extraTeam teamEmail" id="team-email__three">Extra Team email</td>
</tr>
<tr>
<td class="extraTeam teamPhone" id="team-phone__three">111.222.6666</td>
</tr>
</table>
</tr>
</table>
<table class="signature selectable" id="banner-table">
<tr class="tr__banner-opt banner-hidden" id="tr__banner-opt__one">
<td class="td__banner-opt" id="td__banner-opt__one">Banner One</td>
</tr>
<tr class="tr__banner-opt banner-hidden" id="tr__banner-opt__two">
<td class="td__banner-opt" id="td__banner-opt__two">Banner Two</td>
</tr>
<tr class="tr__banner-opt banner-hidden" id="tr__banner-opt__three">
<td class="td__banner-opt" id="td__banner-opt__three">Banner Three</td>
</tr>
<tr class="tr__banner-opt banner-hidden" id="tr__banner-opt__four">
<td class="td__banner-opt" id="td__banner-opt__four">Banner Four</td>
</tr>
<tr class="tr__banner-opt banner-hidden" id="tr__banner-opt__five">
<td class="td__banner-opt" id="td__banner-opt__five">Banner Five</td>
</tr>
<tr class="tr__banner-opt banner-hidden" id="tr__banner-opt__six">
<td class="td__banner-opt" id="td__banner-opt__six">Banner Six</td>
</tr>
</table>
</div>
</div>
</div>
The answer to this question has ended up being to reframe the way I build functions, which is what I expected.
Instead of just doing switchClass functions with a million variables, I ended up learning about loops and using variables set as strings containing HTML that I used .replace to dynamically populate these templates with user-input content each time they click the button.
I would put the code in this post, but it's too large unfortunately.
Here's a replit: https://replit.com/#slingtc/Email-Signature?v=1
Related
I have a chess form with six fields. Two are drop down menus to select names (whiteplayername and blackplayername) and the other four can be used to add a custom name instead (firstnamewhite, lastnamewhite, firstnameblack, lastnameblack). Currently, I want my javascript to disable the custom fields if a name has been selected from the drop down menu (this is working). I also want the submit button to be disabled if neither the whiteplayername or firstnamewhite and blackplayername of firstnameblack is selected. Currently, the submit-button becomes enabled if a name is selected from both the blackplayername and whiteplayname menus but then does not become disabled again if an empty field is selected in either.
Edit
The full html is below, though I have taken out a section just made up of text and rows from the table in order to cut down on the space used.
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>chessopenings3</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<style>
body {
style: "background-color: #FF0000;
}
.topnav {
position: relative;
overflow: hidden;
background-color: #333;
border: 2px;
width: max-content;
}
.topnav a {
float: left;
color: #f2f2f2;
text-align: center;
padding: 14px 16px;
text-decoration: none;
font-size: 17px;
border: 2px;
}
.topnav a:hover {
background-color: #ddd;
color: black;
border: 2px;
}
.formformat {
color: white;
padding: 50px;
font-size: 24px;
font-family: Arial, Helvetica, sans-serif;
}
.instructions-text {
position: absolute;
color: white;
align: center;
left: 750px;
top: 150px;
font-family: Arial, Helvetica, sans-serif;
font-size: 20px;
}
.warning {
position: absolute;
color: white;
text-align: left;
left: 150px;
top: 50px;
font-family: Arial, Helvetica, sans-serif;
font-size: 20px;
}
select {
width: 120px;
}
select:focus {
min-width: 120px;
width: auto;
}
#media screen and (max-width: 500px) {
.navbar a {
float: none;
display: block;
}
}
</style>
<script>
document.addEventListener("DOMContentLoaded", function () {
let isformvalid = false;
document.getElementById("submit-button").disabled = !isformvalid;
document.getElementById("whiteplayername").addEventListener("change", function () {
let blackplayername =
document.getElementById("blackplayername");
let firstnameblack =
document.getElementById("firstnameblack");
let firstnamewhite =
document.getElementById("firstnamewhite");
let lastnamewhite =
document.getElementById("lastnamewhite");
let lastnameblack =
document.getElementById("lastnameblack");
disablewhenmandatorynamemissingwhitename(this.value, blackplayername, firstnameblack, firstnamewhite, lastnameblack, lastnamewhite);
isformvalid = checkeitherfirstorfullnamepopulated (this.value, firstnamewhite, blackplayername, firstnameblack, isformvalid);
document.getElementById("submit-button").disabled = !isformvalid;
});
});
function disablewhenmandatorynamemissingwhitename(whiteplayername, blackplayername, firstnameblack, firstnamewhite, lastnameblack, lastnamewhite) {
if (whiteplayername !== "") {
firstnamewhite.disabled = true;
lastnamewhite.disabled = true;
} else {
firstnamewhite.disabled = false;
lastnamewhite.disabled = false;
}
}
function disablewhenmandatorynamemissingblackname(whiteplayername, blackplayername, firstnameblack, firstnamewhite, lastnameblack, lastnamewhite) {
if (blackplayername !== "") {
firstnameblack.disabled = true;
lastnameblack.disabled = true;
} else {
firstnameblack.disabled = false;
lastnameblack.disabled = false;
}
};
function checkeitherfirstorfullnamepopulated(whiteplayername, firstnamewhite, blackplayername, firstnameblack, isformvalid) {
if ((whiteplayername === "" || whiteplayername === null) && (firstnamewhite.trim() === "")) {
return false;
}
else if ((blackplayername === "" || blackplayername === null) && (firstnameblack.trim() === "")) {
return false;
}
return true;
};
</script>
<body style="background-color:rgb(68, 57, 57);">
<div class="warning">
<p id="warningtext"></p><br>
</div>
<div class="topnav">
<a th:href="#{main.html}"><i class="material-icons"
style="border:2px;font-size:60px;color:rgb(0, 0, 0);">arrow_back</i></a>
</div>
<div class="formformat">
<form th:object="${game}" th:action="#{/addgame}" th:method="post">
<label for="whiteplayername">Select white player:</label>
<select name="whiteplayername" id="whiteplayername" th:object="${names}" th:field="${game.whitePlayerName}">
<option th:value="null" th:selected="${game.name == null}"></option>
<th:block th:each="name : ${names}">
<option th:value="${name.name}"
th:text="${name.name}"></option>
</th:block>
</select>
<label for="blackplayername">Select black player:</label>
<select name="blackplayername" id="blackplayername" th:object="${names}" th:field="${game.blackPlayerName}">
<option th:value="null" th:selected="${game.name == null}"></option>
<th:block th:each="name : ${names}">
<option th:value="${name.name}"
th:text="${name.name}"></option>
</th:block>
</select><br><br>
<label for="firstnamewhite">First name white:</label>
<input type="text" id="firstnamewhite" th:field="*{firstNameWhite}"/>
<label for="firstnameblack">First name black:</label>
<input type="text" id="firstnameblack" th:field="*{firstNameBlack}"/><br><br>
<label for="lastnamewhite">Last name white:</label>
<input type="text" id="lastnamewhite" th:field="*{lastNameWhite}"/>
<label for="lastnameblack">Last name black:</label>
<input type="text" id="lastnameblack" th:field="*{lastNameBlack}"/><br><br>
<label for="date">Date:</label><br>
<input type="date" id="date" th:field="*{date}">
<table>
<tr>
<th>Move</th>
<th>White</th>
<th>Black</th>
</tr>
<tr>
<td>1</td>
<td><input type="text" id="white1" th:field="*{moves}"></td>
<td><input type="text" id="black1" th:field="*{moves}"></td>
</tr>
</table>
<input type="submit" value="Submit" id="submit-button">
</form>
</div>
<br><br>
</body>
</html>
Here's a solution that should meet all your requirements:
<script type="module">
const form = document.getElementById("form");
const submitButton = document.getElementById("submitbutton");
const whitePlayerName = document.getElementById("whiteplayername");
const blackPlayerName = document.getElementById("blackplayername");
const firstNameBlack = document.getElementById("firstnameblack");
const firstNameWhite = document.getElementById("firstnamewhite");
const lastNameWhite = document.getElementById("lastnamewhite");
const lastNameBlack = document.getElementById("lastnameblack");
form.addEventListener('change', () => {
const whiteNameSelected = whitePlayerName.value;
// Disable white name inputs if white name is selected in the dropdown
firstNameWhite.disabled = whiteNameSelected;
lastNameWhite.disabled = whiteNameSelected;
// Determine if the white name is either selected or typed in the inputs
const validWhiteName = whiteNameSelected || (firstNameWhite.value && lastNameWhite.value);
const blackNameSelected = blackPlayerName.value;
// Disable black name inputs if black name is selected in the dropdown
firstNameBlack.disabled = blackNameSelected;
lastNameBlack.disabled = blackNameSelected;
// Determine if the black name is either selected or typed in the inputs
const validBlackName = blackNameSelected || (firstNameBlack.value && lastNameBlack.value);
const submitAvailable = validWhiteName && validBlackName;
submitButton.disabled = !submitAvailable;
});
</script>
<form th:object="${game}" th:action="#{/addgame}" th:method="post" id="form">
<label for="whiteplayername">Select white player:</label>
<select name="whiteplayername" id="whiteplayername" th:object="${names}" th:field="${game.whitePlayerName}">
<option th:value="null" th:selected="${game.name == null}"></option>
<option value="name1">Name 1</option>
<option value="name2">Name 2</option>
</select>
<label for="blackplayername">Select black player:</label>
<select name="blackplayername" id="blackplayername" th:object="${names}" th:field="${game.blackPlayerName}">
<option th:value="null" th:selected="${game.name == null}"></option>
<option value="name1">Name 1</option>
<option value="name2">Name 2</option>
</select><br><br>
<label for="firstnamewhite">First name white:</label>
<input type="text" id="firstnamewhite" th:field="*{firstNameWhite}"/>
<label for="firstnameblack">First name black:</label>
<input type="text" id="firstnameblack" th:field="*{firstNameBlack}"/><br><br>
<label for="lastnamewhite">Last name white:</label>
<input type="text" id="lastnamewhite" th:field="*{lastNameWhite}"/>
<label for="lastnameblack">Last name black:</label>
<input type="text" id="lastnameblack" th:field="*{lastNameBlack}"/><br><br>
<label for="date">Date:</label><br>
<input type="date" id="date" th:field="*{date}">
<button id="submitbutton" disabled>Submit</button>
</form>
It works by combining all the logic into a single handler for the entire form change. Then, if a name is selected in the dropdown, it disables the custom name fields, if not, it leaves them enabled. The code checks to make sure both white and black name are valid and depending on that sets the submit button enabled/disabled state.
You didn't post your whole HTML so I added the button by hand and also your selects are populated dynamically so I had to hardcode some options in them. Please, for Stack Overflow questions, always post examples reproducible by other people to aid them in helping you.
Can you provide the html code too? I also recommend to name properly ur variables and fucntions beacuase are pretty illegibles by the way. Try to type the first letter of each word that compunds the varibale in uppercase at least.
Instead of:
let firstnameblack
Do:
let firstNameBlack
I also recommend to put 2 or 3 letters according to what specifies this varibale, for example if it's a button, do:
let btnFirstNameBlack
Anyways if you can provide the html code maybe I can help you with the button issue.
I am trying to copy a string from notepad to HTML form on base of new line but it is not working for me, below is the code snippet for your help. First Line Should Populate in Field 1, 2nd in Field 2 and 3rd in Field 3
$("input[name=query]").on("paste", function() {
var $this = $(this);
setTimeout(function() {
var id = $this.attr("id"), no = parseInt(id.substr(5)),
//groups = $this.val().split(/\s+/);
//groups = $this.val().split('.');
groups = $this.val().split(/[\n\r]/g);
if (groups) {
var i = 0;
while (no <= 3 && i < groups.length) {
$("#input" + no).val(groups[i]);
++no;
++i;
}
}
}, 0);
});
form {
width: 500px;
margin: 50px auto 0;
}
form h2 {
text-align: center;
text-decoration: underline;
}
form table {
width: 100%;
}
form input {
width: 100%;
height: 40px;
border-radius: 5px;
outline: none;
padding: 0 15px;
border: 1px solid #000000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<form name="form1" action="#" method="get" target="">
<h2>Copy/Paste String</h2>
<table cellpadding="0" cellspacing="20">
<tr>
<td width="100px"><h3>Line 1:</h3></td>
<td><input id="input1" name="query" placeholder="Line 1" type="text"></td>
</tr>
<tr>
<td width="100px"><h3>Line 2:</h3></td>
<td><input id="input2" name="query" placeholder="Line 2" type="text" ></td>
</tr>
<tr>
<td width="100px"><h3>Line 3:</h3></td>
<td><input id="input3" name="query" placeholder="Line 3" type="text"></td>
</tr>
</table>
</form>
Below is the 3 lines I am trying to copy from notepad behavior is new line
This is Line 1
This is Line 2
This is Line 3
Kindly have a look into snippet and guide, where I am doing mistake
The problem with that is your line breaks are being lost when you paste into the (single-line) inputs; only textareas will preserve line breaks; normal inputs will collapse multi-line text into a single line.
The solution is to read the pasted input not from the input but via the clipboardData() area of the event - not the contrived jQuery event, but the original (native) event. jQuery exposes this via the originalEvent property.
This also means you can avoid the timeout hack. All in all:
let fields = $('input[name=query]');
$(document).on('paste', 'input[name=query]', evt => {
evt.preventDefault();
let pasted = evt.originalEvent.clipboardData.getData('text/plain');
pasted.split(/\n/).forEach((line, i) => fields[i].value = line);
});
Fiddle
(Further reading: my blog post about hacking incoming clipboard data.)
You can try this :
$("input[name=query]").on("paste", function(e) {
// Stop data actually being pasted into div
e.stopPropagation();
e.preventDefault();
// Get pasted data via clipboard API
pastedData = window.event.clipboardData.getData('Text');
// Do whatever with pasteddata
var $this = $(this);
setTimeout(function() {
var id = $this.attr("id"), no = parseInt(id.substr(5)),groups = pastedData.split("\n");
if (groups) {
var i = 0;
while (no <= 3 && i < groups.length) {
$("#input" + no).val(groups[i]);
++no;
++i;
}
}
}, 0);
});
Good luck!
I have a Radio button. I want to implement a validation on "Submit" Anchor tag that displays an error if no selection is made on the radio button and redirects to the URL provided in the href attribute if the radio button selection is made.
Below is the code for radio button -
<div>
<input required="" type="radio" id="group02-0" name="group02" value="Yes" onclick="yesnoCheck();">
<label for="group02-0" >Yes</label>
<input type="radio" id="group02-1" name="group02" value="No" onclick="yesnoCheck();">
<label for="group02-1">No</label>
</div>
<script>
var radio_value = "";
function yesnoCheck() {
radio_value = document.querySelector('input[name="group02"]:checked').value;
}
</script>
In the same HTML file, I have code for the Submit Anchor tag -
<span>Submit</span>
<script>
function submitCheck() {
if (radio_value === "") {
//Display an error. The user should not be taken to the next page
return false;
} else {
//User should be taken to the URL in the href attribute
return true;
}
}
</script>
Irrespective of whether I make a selection on the radio button, the anchor tag always takes me to the next page. Please help!
You don't need two radio buttons. Only one Checkbox.
Use Event.preventDefault() to prevent default browser navigation
Use the input element's checked state to determine the outcome
Finally use document.location to navigate to a EL_submitBtn.getAttribute('href')
PS: Don't use inline JavaScript (in HTML). JS should be in one place and that's your JS file or inside a <script> tag. It's easier to debug and maintain.
Single checkbox
const EL_submitBtn = document.querySelector('#submitBtn');
const EL_acceptCkb = document.querySelector('[name="accept"]');
function submitCheck(ev) {
ev.preventDefault(); // prevent follow link
if (!EL_acceptCkb.checked) { // Unchecked
alert("You will not get a better UX");
} else { // Checked
alert("Yes! Buckle up!")
document.location = EL_submitBtn.getAttribute('href');
}
}
EL_submitBtn.addEventListener('click', submitCheck);
<div>
<h3>Would you like a better UX?</h3>
<label>
<input type="checkbox" name="accept"> Yes I do
</label>
</div>
<a id="submitBtn" href="https://www.google.com">Submit</a>
Two radio buttons
Use document.querySelector('[name="accept"]:checked') to get the checked one, if any.
const EL_submitBtn = document.querySelector('#submitBtn');
function submitCheck(ev) {
ev.preventDefault(); // prevent follow link
const EL_acceptCkd = document.querySelector('[name="accept"]:checked');
if (!EL_acceptCkd) { // None checked
alert("You must select Yes or No.");
} else if (EL_acceptCkd.value === 'no') { // "NO" checked
alert("You will not get a better UX");
} else { // "YES" checked
alert("Yes! Buckle up!")
document.location = EL_submitBtn.getAttribute('href');
}
}
EL_submitBtn.addEventListener('click', submitCheck);
<div>
<h3>Would you like a better UX?</h3>
<label>
<input type="radio" name="accept" value="yes"> Yes
</label>
<label>
<input type="radio" name="accept" value="no"> No
</label>
</div>
<a id="submitBtn" href="https://www.google.com">Submit</a>
use css pointer-events: none; -> https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events
If you absolutely want to use button radios (even if it's a bit twisted as an idea) here is the code:
const aHrefGoogle = document.getElementById('aHrefGoogle');
document.querySelectorAll('input[name=group02]').forEach(el=>
{
el.onchange=_=>{ if (el.checked) setLinkOnOff(el.value) }
})
function setLinkOnOff(val)
{
if (val==='yes') { aHrefGoogle.classList.remove('adisableHref') }
else { aHrefGoogle.classList.add('adisableHref') }
}
.adisableHref {
color: grey;
pointer-events: none;
cursor: default;
text-decoration-line: none;
}
make link Google active ?
<label ><input type="radio" name="group02" value="yes">Yes </label>
<label ><input type="radio" name="group02" value="no" checked>No! </label>
<br><br>
<span> Google </span>
for memo here is the initial code with a checkbox :
const yesnoCheck = document.getElementById('yesnoCheck')
, aHrefGoogle = document.getElementById('aHrefGoogle')
;
// init
yesnoCheck.checked = false
aHrefGoogle.classList.add('adisableHref')
yesnoCheck.oninput =_=>
{
if (yesnoCheck.checked) { aHrefGoogle.classList.remove('adisableHref') }
else { aHrefGoogle.classList.add('adisableHref') }
}
#yesnoCheck { display: none; }
#yesnoCheck + label { display: inline-block; background: #cd3c3c; color: white; padding: .17em .2em; cursor: pointer; }
#yesnoCheck:checked + label { background: #378b2c; }
#yesnoCheck + label::before { content: 'NO'; display: inline-block; width:2.6em; text-align: center; }
#yesnoCheck + label::after { content: ''; display: inline-block; width:0; text-align: center; }
#yesnoCheck:checked + label::before { content: ''; width:0; }
#yesnoCheck:checked + label::after { content: 'YES'; width:2.6em; }
.adisableHref {
color: grey;
pointer-events: none;
cursor: default;
text-decoration-line: none;
}
make link Google active ?
<input type="checkbox" id="yesnoCheck"><label for="yesnoCheck">▉</label>
<br><br>
<span> Google </span>
For my example I have three functions that must execute completely before going to the next function. I know I can place the second function in the first function, etc, but I need the flexibility to execute functions in various orders.
Upon doing research it appears I need to do a "Callback" but don't understand how to apply it to my situation. Here is what I have so far. Of course the way it is it goes through all three functions without stopping other than for the alerts. Can someone help me here or at least point me in the direction I should consider?
<!DOCTYPE html>
<html>
<body>
<h3>Validates Input Values</h3>
<form name='checkout_form'>
<table id="table_form">
<tr>
<td>First Name:</td>
<INPUT type="text" id="xFirstName" STYLE="color: #3366CC; text-align: left; font-family: Times; font-size: 12px; background-color: transparent; border:dotted; border-color:#7b0000; border-width:1px; width:180px" name="first_name" value="" size="14" onKeyup="autotab(this,document.donate_form.last_name)"
maxlength=14 onkeypress="return inputLimiter(event,'NameCharacters')">
</td>
</tr>
<tr>
<td>Last Name:</td>
<td>
<INPUT type="text" id="xLastName" STYLE="color: #3366CC; text-align: left; font-family: Times; font-size: 12px; background-color: transparent; border:dotted; border-color:#7b0000; border-width:1px; width:180px" name="last_name" value="" size="14" onKeyup="autotab(this,document.donate_form.amount)"
maxlength=14 onkeypress="return inputLimiter(event,'NameCharacters')">
</td>
</tr>
<tr>
<td>Zip Code:</td>
<td>
<INPUT type="text" id="xZipCode" STYLE="color: #3366CC; text-align: left;
font-family: Times; font-size: 12px; background-color: transparent; border:dotted; border-color:#7b0000; border-width:1px; width:180px" name="zip" value="" size="14" onKeyup="autotab(this,document.donate_form.amount)" maxlength=14 onkeypress="return inputLimiter(event,'Numbers')">
</td>
</tr>
</table>
</form>
<button onclick="myFunction_Varify()">VALIDATE</button>
<script>
function myFunction_Varify() {
myFunction_firstName();
myFunction_lastName();
myFunction_zipCode();
}
function myFunction_firstName() {
vFirstName = document.getElementById("xFirstName").value;
if (vFirstName == "") {
document.forms['checkout_form'].elements['first_name'].focus();
alert("No FIRST NAME entered");
}
}
function myFunction_lastName() {
vLastName = document.getElementById("xLastName").value;
if (vLastName == "") {
document.forms['checkout_form'].elements['last_name'].focus();
alert("No LAST NAME entered");
return false;
}
}
function myFunction_zipCode() {
vZipCode = document.getElementById("xZipCode").value;
if (vZipCode == "") {
document.forms['checkout_form'].elements['zip'].focus();
alert("No ZIP CODE entered");
return false;
}
}
</script>
</body>
</html>
you are && them
function myFunction_Varify() {
myFunction_firstName() && myFunction_lastName() && myFunction_zipCode();
}
function myFunction_firstName() {
vFirstName = document.getElementById("xFirstName").value;
if (vFirstName == "") {
document.forms['checkout_form'].elements['first_name'].focus();
alert("No FIRST NAME entered");
return false;
}
return true;
}
function myFunction_lastName() {
vLastName = document.getElementById("xLastName").value;
if (vLastName == "") {
document.forms['checkout_form'].elements['last_name'].focus();
alert("No LAST NAME entered");
return false;
}
return true;
}
function myFunction_zipCode() {
vZipCode = document.getElementById("xZipCode").value;
if (vZipCode == "") {
document.forms['checkout_form'].elements['zip'].focus();
alert("No ZIP CODE entered");
return false;
}
return true;
}
I am having trouble trying to convert this into an array. I don't fully understand how to take input from a form and save it in an array.
My project states: Do NOT save the input in a set of variables and then put those in an array.
Use the array as your collection of data saving variables. (That is what a data
structure is for.)
I have looked for the last 2 hours trying to find something to help me. I have to do this project in JavaScript, but keep finding jquery and I'm not quite sure on how to convert it to Javascript
Any suggestions on how I can take the form input and save it in an array?
This is only a little bit of my project. I just took the first function and the HTML that is attached to the function.
Code in the snippet.
function getID() {
var studentID = new Array();
studentID = document.forms["getFormInfo"]["txtStudentID"].value;
var numberOnly = /^[0-9]+$/;
//Checks for a null/blank within Student ID: field.
if (studentID.length == 0) {
document.getElementById('divAllField').style.display = '';
document.forms["getFormInfo"]["txtStudentID"].focus();
return false;
} //End of if statement
else {
if (studentID.length == 8 && studentID.match(numberOnly)) {
//Run the next function
getFirstName();
} //End of else/if statement
else {
//Show Error Message
document.getElementById('divStudentID').style.display = "";
//Focus on input field with the error.
document.forms["getFormInfo"]["txtStudentID"].focus();
} //end of else/if/else statement
} //End of else statement
} //End of function getID()
h1 {
text-align: center;
color: teal;
}
table {
border-spacing: 8px;
border: 2px solid black;
text-align: justify;
}
th {
text-align: center;
padding: 8px;
color: blue;
font-size: 125%;
}
td {
padding: 5px;
}
input,
select {
width: 200px;
border: 1px solid #000;
padding: 0;
margin: 0;
height: 22px;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
input {
text-indent: 2px;
}
label {
float: left;
min-width: 115px;
}
div {
padding: 3px;
color: red;
font-size: 80%;
}
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Begining of the header -->
</head>
<!-- End of the header -->
<body>
<!-- Everything in the <body> </body> displays on the webpage -->
<form id="getFormInfo">
<!-- Creates a form with an ID -->
<table id="tableInfo">
<!-- Creates a table within the form -->
<!-- Creates a table header within the form and table -->
<th>User Information</th>
<!-- Error Message for all fields if they are null/blank -->
<tr>
<td><strong><div id="divAllField" style="display: none;">
Please make sure all input boxes are filled out.
</div></strong>
</td>
</tr>
<!-- Student ID Input -->
<tr>
<td><strong><label>Student ID:</label></strong>
<input type="text" name="txtStudentID" maxlength="8" placeholder="8 Digit ID" value="00149371" required>
<!-- Error Message for Student ID -->
<strong><div id="divStudentID" style="display: none;">
Please enter your 8 Digit Student ID. (Whole Numbers Only)</br>
Example: 00123456
</div></strong>
</td>
</tr>
<tfoot>
<td>
<input type="button" onclick="getID();" value="Submit">
</tfoot>
</td>
</table>
<!-- End of tableInfo -->
</form>
<!-- End of getInfo -->
</body>
</html>
Anyone know how I can save the input from the form and save it into an array?
Please help, I've been working on this project for over 10 hours.
Use the push function to add items to the array.
function getID() {
var studentID = [];
var tstStudentIdVal = document.forms["getFormInfo"]["txtStudentID"].value
studentID.push(tstStudentIdVal);
var numberOnly = /^[0-9]+$/;
//Checks for a null/blank within Student ID: field.
if (tstStudentIdVal.length == 0) {
document.getElementById('divAllField').style.display = '';
document.forms["getFormInfo"]["txtStudentID"].focus();
return false;
} //End of if statement
else {
if (tstStudentIdVal.length == 8 && tstStudentIdVal.match(numberOnly)) {
//Run the next function
getFirstName();
} //End of else/if statement
else {
//Show Error Message
document.getElementById('divStudentID').style.display = "";
//Focus on input field with the error.
document.forms["getFormInfo"]["txtStudentID"].focus();
} //end of else/if/else statement
} //End of else statement
} //End of function getID()
If you can't use jQuery, I think the most elegant solution is to use querySelectorAll() to get a nodeList of all your inputs, then use a combination of Function.prototype.call() and Array.prototype.map() to translate the array of inputs into an array of your own design.
In the snippet below, the resulting array has objects each which have a name and value, which come directly from the text inputs in your form (your question isn't quite clear on how the resulting array should look).
function getID() {
var nodes = document.forms["getFormInfo"].querySelectorAll("input[type='text']");
var array = [].map.call(nodes, function(item) {
return {name : item.name, value : item.value};
});
console.log(array);
}
<form id="getFormInfo">
<input type="text" name="txtStudentID"/>
<input type="text" name="firstName"/>
<input type="text" name="lastName"/>
<input type="button" onclick="getID();" value="Submit"/>
</form>