Highlight a table row if radio button has not been checked - javascript

Problem:
I have one table per tab (5 tabs in total) where each consists of three rows (one table header and two table data).
I wish to execute a JS script that scans only table rows that has the attribute id and then checks the radio buttons inside this row. If none has been selected then the table row should change color by adding a class to it.
Minimal (Working) Example:
HTML
<table class="table table-striped table-borderless" id="survey">
<thead class="text-center">
<tr>
<th scope="col"></th>
<th scope="col">1</th>
<th scope="col">2</th>
<th scope="col">3</th>
<th scope="col">4</th>
<th scope="col">5</th>
</tr>
</thead>
<tbody>
<tr id="1">
<td scope="row">Question 1</td>
<td><input type="radio" name="1" id="1" value="1"></td>
<td><input type="radio" name="1" id="1" value="2"></td>
<td><input type="radio" name="1" id="1" value="3"></td>
<td><input type="radio" name="1" id="1" value="4"></td>
<td><input type="radio" name="1" id="1" value="5"></td>
</tr>
<tr id="2">
<td scope="row">Question 2</td>
<td><input type="radio" name="2" id="2" value="1"></td>
<td><input type="radio" name="2" id="2" value="2"></td>
<td><input type="radio" name="2" id="2" value="3"></td>
<td><input type="radio" name="2" id="2" value="4"></td>
<td><input type="radio" name="2" id="2" value="5"></td>
</tr>
</tbody>
</table>
JavaScript
The function is called upon by a button in HTML when a user attempts to switch a tab.
validateForm() {
var valid = true;
var rows = Nodes.tab[this.currentTab].querySelectorAll('tr[id]');
for (var i = 0; i < rows.length; i++) {
var inputs = rows[i].querySelectorAll("input");
for (var x = 0; x < inputs.length; x++) {
// Add class to table row?
}
}
// If valid then mark step with green color
if (valid) {
document.getElementsByClassName("step")[this.currentTab].classList.add("finish");
}
// Return the valid status
return valid;
}
Desired output:
If a user does not check at least one radio button of a button group then add the CSS class "error" to that table row.

Just elaborating on my comments about exploiting the browser's native form validation to write less code.
Pure CSS and HTML solution:
<style>
#form1:invalid ~ table #row1 {
background-color: red;
}
#form2:invalid ~ table #row2 {
background-color: red;
}
</style>
<form id="form1"></form>
<form id="form2"></form>
<table class="table table-striped table-borderless" id="survey">
<thead class="text-center">
<!--...-->
</thead>
<tbody>
<tr id="row1">
<td scope="row">Question 1</td>
<td><input type="radio" name="f1" value="1" required form="form1"></td>
<td><input type="radio" name="f1" value="2" form="form1"></td>
<td><input type="radio" name="f1" value="3" form="form1"></td>
<td><input type="radio" name="f1" value="4" form="form1"></td>
<td><input type="radio" name="f1" value="5" form="form1"></td>
</tr>
<tr id="row2">
<td scope="row">Question 2</td>
<td><input type="radio" name="f2" value="1" required form="form2"></td>
<td><input type="radio" name="f2" value="2" form="form2"></td>
<td><input type="radio" name="f2" value="3" form="form2"></td>
<td><input type="radio" name="f2" value="4" form="form2"></td>
<td><input type="radio" name="f2" value="5" form="form2"></td>
</tr>
</tbody>
</table>
And if you really need JavaScript to know what's going on, you can call this to determine if a radio group has a value:
document.getElementById('form1').checkValidity()
It will return false if no radio in the group is selected.

Related

How to have an onClick event fire for certain radio button children of a <tr>

I have a table row inside of a table. Inside this table row I have 4 buttons. I want to use jquery to fire an onClick for any button in the row except for the 1st one. Is there an easy way to select the <tr> itself instead of recreating an onClick for every button?
<table class="table table-striped stickeyHeaders">
<tr id="buttonRow">
<td><input type="radio" name="SelectedStoreRoles" class="store-privs" value="1"/>
<td><input type="radio" name="SelectedStoreRoles" class="store-privs" value="2"/>
<td><input type="radio" name="SelectedStoreRoles" class="store-privs" value="3"/>
<td><input type="radio" name="SelectedStoreRoles" class="store-privs" value="4"/>
</tr>
</table>
Here is my general though process but need some help to flesh it out all the way
$('#buttonRow').children("Some Filter that says value > 1").On('Click, function({}));
You can use the :gt selector to avoid the first element:
$('#buttonRow').find(":radio:gt(0)").on('click', e => {
console.log(e.target.value);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<table class="table table-striped stickeyHeaders">
<tr id="buttonRow">
<td><input type="radio" name="SelectedStoreRoles" class="store-privs" value="1" /></td>
<td><input type="radio" name="SelectedStoreRoles" class="store-privs" value="2" /></td>
<td><input type="radio" name="SelectedStoreRoles" class="store-privs" value="3" /></td>
<td><input type="radio" name="SelectedStoreRoles" class="store-privs" value="4" /></td>
</tr>
</table>
You can use a combination of :not and :first-child pseudo-classes
$('#buttonRow')
.children('td:not(:first-child)')
.children('input')
.on('click', function() {
console.log(this)
})

JS .checked not working in for ... in loop - in IE11

I have the following function which works great in chrome, but in IE 11 doesn't.
It is designed to:
Take a questionGroup value determining which group of questions we want an average score for
Get a collections of the inputs on the page
Loop through them
If they are 'checked' then get the class name which determines the group the question is in
Count the number of questions in the group we're looking for
Get the total score for all questions in the group
Divide the total score by the number of questions to get the average score for the group
function getGroupScore(questionGroup) {
var inputs = document.getElementsByTagName("input");
var countOfQs = 0;
var totalGroupScore = 0;
for (var element in inputs) {
if (inputs[element].checked) {
var theQuestionsGroup = inputs[element].className;
if (theQuestionsGroup == questionGroup) {
var answer = parseInt(inputs[element].value)
totalGroupScore += answer;
countOfQs++;
}
}
}
var groupScore = totalGroupScore / countOfQs;
return groupScore;
}
In debugging, the loop seems to never get passed the following stage:
if (inputs[element].checked)
Even though there are input fields that are checked
example of the form I'm looping through:
<form action="">
<table style="margin: 0 auto; border: none;" id="reschecklist">
<tbody>
<tr>
<td rowspan="3" valign="top" width="400"><h3>Questions</h3></td>
<td colspan="5" class="center"><h3>Score</h3></td>
</tr>
<tr>
<td colspan="2" class="left"><strong>(not at all)</strong></td>
<td colspan="3" align="right" class="right"><strong>(I am fully implementing this)</strong></td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td class="heading" width="400"><strong>Minimise overhead costs</strong></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td class="question"><p>Do you consider and identify ways to maintain machinery better and cheaper?</p></td>
<td><input type="radio" name="q1" value="1" class="grp1" /></td>
<td><input type="radio" name="q1" value="2" class="grp1" /></td>
<td><input type="radio" name="q1" value="3" class="grp1" /></td>
<td><input type="radio" name="q1" value="4" class="grp1" /></td>
<td><input type="radio" name="q1" value="5" class="grp1" /></td>
</tr>
<tr>
<td class="question"><p>Do you regularly review your overhead costs i.e. can you identify how much they cost you on a monthly, 6 monthly, annual basis?</p></td>
<td><input type="radio" name="q2" value="1" class="grp1" /></td>
<td><input type="radio" name="q2" value="2" class="grp1" /></td>
<td><input type="radio" name="q2" value="3" class="grp1" /></td>
<td><input type="radio" name="q2" value="4" class="grp1" /></td>
<td><input type="radio" name="q2" value="5" class="grp1" /></td>
</tr>
<tr>
<td class="heading" width="400"><strong>Set goals and budgets</strong></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td class="question"><p>Do you have a clearly set out vision and objectives for the business?</p></td>
<td><input type="radio" name="q3" value="1" class="grp2" /></td>
<td><input type="radio" name="q3" value="2" class="grp2" /></td>
<td><input type="radio" name="q3" value="3" class="grp2" /></td>
<td><input type="radio" name="q3" value="4" class="grp2" /></td>
<td><input type="radio" name="q3" value="5" class="grp2" /></td>
</tr>
<tr>
<td class="question"><p>Do you routinely (every 3-6 months), with your partner/s or your team, take a hands off view of the business and discuss objectives, performance etc?</p></td>
<td><input type="radio" name="q4" value="1" class="grp2" /></td>
<td><input type="radio" name="q4" value="2" class="grp2" /></td>
<td><input type="radio" name="q4" value="3" class="grp2" /></td>
<td><input type="radio" name="q4" value="4" class="grp2" /></td>
<td><input type="radio" name="q4" value="5" class="grp2" /></td>
</tr>
for-in is not how you loop through an HTMLCollection. Use a simple for or one of the "array like" approaches in this answer (which also explains why for-in isn't the right choice here). I suspect the problem is that there are no enumerable properties in the HTMLCollection on the platform where you're seeing the problem.
So for instance:
for (var element = 0 ; element < inputs.length; ++elements) {
In modern environments, HTMLCollection (what you get back from getElementsByTagName) may have the non-standard extension making it iterable (ES2015+) and giving it a forEach. If not, you can easily add it:
if (typeof NodeList !== "undefined" &&
NodeList.prototype &&
!NodeList.prototype.forEach) {
// Yes, direct assignment is fine here, no need for `Object.defineProperty`
NodeList.prototype.forEach = Array.prototype.forEach;
}
if (typeof HTMLCollection !== "undefined" &&
HTMLCollection.prototype &&
!HTMLCollection.prototype.forEach) {
// Yes, direct assignment is fine here, no need for `Object.defineProperty`
HTMLCollection.prototype.forEach = Array.prototype.forEach;
}
That code does both HTMLCollection and NodeList (what you get from querySelectorAll). Then you can use:
inputs.forEach(function(input) {
if (input.checked) {
// ...
}
});

Ajax updatet score from input value

I am trying to create a form with three "Likert Scale" input.
For all three input field there is totaly 10 points that can be devided on the three "Likert scale" inputs. When this score is equal to 0, the submit button should be enabled and the form can be submitted. The number of points left should be updated without having the page reloade using ajax, so the user will know how many points that are left.
I have not really figured out how to do this but I have added some pseudo code, to explain this.
$(document).ready(function(e) {
// Initial score/points
var score = 10;
document.getElementById("score").innerHTML = score;
$('input:radio').click(function() {
e.preventDefault();
// update score, based on clicked alternative value
new_score = score - alternative_clicked;
if new_score < 0:
var error = "You do not have enoght points left, choose a smaler number";
document.getElementById("error").innerHTML = error;
else if new_score === 0:
// enable submit button
else :
// update score with new_score value
});
$('input:submit').click(function() {
e.preventDefault();
// send to google spreadsheet
});
});
table.striped-columns tbody td:nth-of-type(even),
table.striped-columns th:nth-of-type(even) {
background: blue;
}
table.striped-columns tbody td:nth-of-type(odd),
table.striped-columns th:nth-of-type(odd) {
background: #fafafa;
}
table.border {
border-collapse: collapse;
border-spacing: 0;
}
table.border td,
table.border th {
border: 1px solid grey;
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- This should be updated -->
<p><b>TOTAL POINTS LEFT:</b> <span id="score"></span></p>
<form method="post" action="/echo/html/" ajax="true">
<table class="striped-columns border">
<thead>
<tr>
<th>TEST</th>
<th>1</th>
<th>2</th>
<th>3</th>
<th>4</th>
<th>5</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alternativ 1</td>
<td><input type="radio" value="1" name="alternativ1" /></td>
<td><input type="radio" value="2" name="alternativ1" /></td>
<td><input type="radio" value="3" name="alternativ1" /></td>
<td><input type="radio" value="4" name="alternativ1" /></td>
<td><input type="radio" value="5" name="alternativ1" /></td>
</tr>
<tr>
<td>Alternativ 2</td>
<td><input type="radio" value="1" name="alternativ2" /></td>
<td><input type="radio" value="2" name="alternativ2" /></td>
<td><input type="radio" value="3" name="alternativ2" /></td>
<td><input type="radio" value="4" name="alternativ2" /></td>
<td><input type="radio" value="5" name="alternativ2" /></td>
</tr>
<tr>
<td>Alternativ 3</td>
<td><input type="radio" value="1" name="alternativ3" /></td>
<td><input type="radio" value="2" name="alternativ3" /></td>
<td><input type="radio" value="3" name="alternativ3" /></td>
<td><input type="radio" value="4" name="alternativ3" /></td>
<td><input type="radio" value="5" name="alternativ3" /></td>
</tr>
</tbody>
</table>
<br>
<input type="submit" value="Submit" />
</form>
Here is a one way to do that:
(sorry for bad indentation in the snippet. Seems it is a bit buggy feature in SO)
I use eval() so I wouldn't need to write many if/else statements.
However - eval() isn’t evil, just misunderstood.
$(document).ready(function(e) {
// Initial score/points
var score = 10;
var a1 = 0, a2 = 0, a3 = 0;
var inputs = $('input');
inputs.each(function(i) {
$(this).on('click', function() {
var clicked = $(this).closest('tr').get(0).id;
score += eval(clicked)
score -= eval(clicked + " = " + $(this).val());
$("#score").html(score);
if (score == 0 && (a1 != 0 && a2 != 0 && a3 != 0)) {
$("#submit").prop("disabled", false);
} else {
$("#submit").prop("disabled", true);
}
})
})
});
table.striped-columns tbody td:nth-of-type(even),
table.striped-columns th:nth-of-type(even) {
background: blue;
}
table.striped-columns tbody td:nth-of-type(odd),
table.striped-columns th:nth-of-type(odd) {
background: #fafafa;
}
table.border {
border-collapse: collapse;
border-spacing: 0;
}
table.border td,
table.border th {
border: 1px solid grey;
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<form method="post" action="/echo/html/" ajax="true">
<table class="striped-columns border">
<thead>
<tr>
<th>TEST</th>
<th>1</th>
<th>2</th>
<th>3</th>
<th>4</th>
<th>5</th>
</tr>
</thead>
<tbody>
<tr id="a1">
<td>Alternativ 1</td>
<td><input type="radio" value="1" name="alternativ1" /></td>
<td><input type="radio" value="2" name="alternativ1" /></td>
<td><input type="radio" value="3" name="alternativ1" /></td>
<td><input type="radio" value="4" name="alternativ1" /></td>
<td><input type="radio" value="5" name="alternativ1" /></td>
</tr>
<tr id="a2">
<td>Alternativ 2</td>
<td><input type="radio" value="1" name="alternativ2" /></td>
<td><input type="radio" value="2" name="alternativ2" /></td>
<td><input type="radio" value="3" name="alternativ2" /></td>
<td><input type="radio" value="4" name="alternativ2" /></td>
<td><input type="radio" value="5" name="alternativ2" /></td>
</tr>
<tr id="a3">
<td>Alternativ 3</td>
<td><input type="radio" value="1" name="alternativ3" /></td>
<td><input type="radio" value="2" name="alternativ3" /></td>
<td><input type="radio" value="3" name="alternativ3" /></td>
<td><input type="radio" value="4" name="alternativ3" /></td>
<td><input type="radio" value="5" name="alternativ3" /></td>
</tr>
</tbody>
</table>
<br>
<input id="submit" type="submit" value="Submit" disabled/>
<div id="score"> 10
</div>
</form>

Javascript table with multiple rows radio button function

I have some trouble to fix this code. I would like to know how can I implement the function to make all the rows working with a radio button.
I do not want to repeat the writing of the code line for each question. I would like something short and clear in DOM scriptiong no Jquery.
Only one option can be selected for one row.
here my js and html code
<!DOCTYPE html>
<html>
<body>
<script>
function checkRadio() {
var selectedAge="";
var len = document.row.selectedAge.length;
var i;
for (i = 0; i<len; i++) {
if (document.row.selectedAge[i].value;
break;
}
}
if (selectedAge == "") {
document.getElementByid("radio_error").innnerHTML = "no option selected";
return false
}
else {
document.getElementById("radio_error").innerHTML = "";
return true;
}
}
</script>
<table>
<tr>
<th scope="col"></th>
<th scope="col">noRisk</th>
<th scope="col">lowRisk</th>
<th scope="col">mediumRisk</th>
<th scope="col">HighRisk</th>
</tr>
<tr>
<th scope="row"><div class="lefttext">How old are you?</div></th>
<td><input type="radio" id="none" name="selectedAge" value="1-25">1-25</td>
<td><input type="radio" id="low" name="selectedAge" value="26-40">26-40</td>
<td><input type="radio" id="medium" name="selectedAge" value="41-60">41-60</td>
<td><input type="radio" id="high" name="selectedAge" value="60+">1-25</td>
</tr>
<tr>
<th scope="row"><div class="lefttext">What is you BMI?</div></th>
<td><input type="radio" id="none" name="selectedBmi1" value="0-25">0-25</td>
<td><input type="radio" id="low" name="selectedBmi2" value="26-30">26-30</td>
<td><input type="radio" id="medium" name="selectedBmi3" value="31-35">31-35</td>
<td><input type="radio" id="high" name="selectedBmi4" value="35+">35+</td>
</tr>
<tr>
<th scope="row"><div class="lefttext">Does anybody in your family have diabetes?</div></th>
<td><input type="radio" id="none" name="selectedDiabete1" value="no">No</td>
<td><input type="radio" id="low" name="selectedDiabete2" value="grandparent">Grandparent</td>
<td><input type="radio" id="medium" name="selectedDiabete3" value="sibling">Sibling</td>
<td><input type="radio" id="high" name="selectedDiabete4" value="parent">Parent</td>
</tr>
<tr>
<th scope="row"><div class="lefttext">How would you describe your diabete</div></th>
<td><input type="radio" id="none" name="description1" value="low sugar">Low sugar</td>
<td><input type="radio" id="low" name="description2" value="normal sugar">Normal sugar</td>
<td><input type="radio" id="medium" name="description3" value="quite high sugar">Quite high sugar</td>
<td><input type="radio" id="high" name="description4" value="high sugar">High sugar</td>
</tr>
</table>
</body>
</html>
Your code has some javascript errors. I solved those errors.
here is your modified script:
<script>
function checkRadio() {
var selectedAge="";
var len = document.row.selectedAge.length;
var i;
function init(){
for (i = 0; i<len; i++) {
if (document.row.selectedAge[i].value);
break;
}
if (selectedAge == "") {
document.getElementByid("radio_error").innnerHTML = "no option selected";
return false
}
else {
document.getElementById("radio_error").innerHTML = "";
return true;
}
}
init();
}
</script>

using ng-model with multiple ng-repeated radio button groups

See JsBin
I have a dynamic list of checkpoints which is generated from ng-repeat, each item has six radio buttons. I need to bind each of these sets to a $scope object.
Below, you can see I've set the name to things like selectedOption1, selectedOption2, etc... This allows each ng-repeated list to be independent of the next. Now, I need to bind the selected option of those selectedOptionX groups to a $scope object, while still maintaining the checkpoint.Name in the object.
<table>
<tbody>
<tr ng-repeat="checkpoint in checkpoints">
<td>{{checkpoint.Name}}</td>
<td><input type="radio" name="selectedOption{{$index}}" value="pass" /></td>
<td><input type="radio" name="selectedOption{{$index}}" value="fail" /></td>
<td><input type="radio" name="selectedOption{{$index}}" value="remediated" /></td>
<td><input type="radio" name="selectedOption{{$index}}" value="nc" ng-checked="true" /></td>
<td><input type="radio" name="selectedOption{{$index}}" value="na" /></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
The output object might be something like:
[
{
Name: "the first checkpoint",
Value: "remediated"
},
{
Name: "the second checkpoint",
Value: "fail"
},
{
Name: "the third checkpoint",
Value: "pass"
},
];
What I've tried...
<td><input type="radio" name="selectedOption{{$index}}" value="pass" ng-model="selectedOption{{$index}}"/></td>
//and
<td><input type="radio" name="selectedOption{{$index}}" value="pass" ng-model="selectedOption[$index]"/></td>
//and
<td><input type="radio" name="selectedOption{{$index}}" value="pass" ng-model="selectedOption.$index"/></td>
//and
<td><input type="radio" name="selectedOption{{$index}}" value="pass" ng-model="checkpoint.Name"/></td>
I've tried some other things, too, but nothing has come close.
http://jsbin.com/haxor/1/edit
<table>
<tbody>
<tr ng-repeat="checkpoint in checkpoints">
<td>{{checkpoint.Name}}</td>
<td><input type="radio" ng-model="checkpoint.selectedOption" value="pass" name="selectedOption{{$index}}"></td>
<td><input type="radio" ng-model="checkpoint.selectedOption" value="fail" name="selectedOption{{$index}}"></td>
<td><input type="radio" ng-model="checkpoint.selectedOption" value="remediated" name="selectedOption{{$index}}"></td>
<td><input type="radio" ng-model="checkpoint.selectedOption" value="nc" name="selectedOption{{$index}}" ng-checked="true"></td>
<td><input type="radio" ng-model="checkpoint.selectedOption" value="nc" ng-checked="true" name="selectedOption{{$index}}"></td>
<td><input type="radio" ng-model="checkpoint.selectedOption" value="x" name="selectedOption{{$index}}"></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
Try this, it will setup selected value inside checkpoints object
http://jsbin.com/barufuhi/3/edit
<div ng-controller="CheckpointsController">
<table>
<tbody>
<tr ng-repeat="checkpoint in checkpoints">
<td>{{checkpoint.Name}}</td>
<td><input type="radio" ng-model="checkpoint.value" value="one"></td>
<td><input type="radio" ng-model="checkpoint.value" value="two"></td>
<td><input type="radio" ng-model="checkpoint.value" value="three"></td>
<td><input type="radio" ng-model="checkpoint.value" value="four"></td>
<td><input type="radio" ng-model="checkpoint.value" value="five"></td>
<td><input type="radio" ng-model="checkpoint.value" value="six"></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>

Categories