Unwanted return from JavaScript functions with DOM - javascript

I am designing a JavaScript function checkForm(), which is meant to check if at least half of the answers of a form have been completed. It returns ”true” if the condition is met and an alert message and ”false” if not. The answers are given in input text fields, whose content mustn't be the empty string in order to be regarded as answered.
In order to make the check, the function checkForm() calls two other functions: totalNumberOfQuestions() and totalCompletedAnswers(), as follows:
function totalNumberOfQuestions() /* Returns the total number of questions in the form */
{ total
numberOfQuestions = 0;
i = 1;
do
{
nameOfAnswer = 'answer_' + i;
if(document.getElementsByName(nameOfAnswer)[0] != null)
{
totalnumberOfQuestions ++;
}
i++;
}
while (document.getElementsByName(nameOfAnswer)[0] != null);
return totalnumberOfQuestions;
}
function totalCompletedAnswers() /* Returns the total number of completed answers in the form */
{
numberOfCompletedAnswers = 0;
i = 1;
for(i = 1; i<= totalNumberOfQuestions(); i++)
{
nameOfAnswer = 'answer_' + i;
if ( form[nameOfAnswer].value != '')
{
numberOfCompletedAnswers ++;
}
}
return numberOfCompletedAnswers;
}
function checkForm()
{
if ( totalCompletedAnswers() < 7 )
{
alert("Please answer at least half of the questions.");
return false;
}
return true;
}
But, surprisingly, the function checkForm() does not work correctly in this form, but returns true even when the number of completed answers is less than a half of the total number of answers. However, the function works properly if the function totalCompletedAnswers() is checked against a constant value, e.g.:
function checkForm()
{
if ( totalCompletedAnswers() < 7 )
{
alert("Please answer at least half of the questions.");
return false;
}
return true;
}
This means that using the function totalNumberOfQuestions() in the body of the checkForm() function is ”importing” some unwanted returned value. This happens even if I call the former separately (x= totalNumberOfQuestions() and then rewriting the condition: if ( totalCompletedAnswers() < x )
). Does anyone know how one can avoid such unwanted returned values when calling a function?

In totalComletedAnswers you have the snippet:
if(numberOfCompletedAnswers < totalNumberOfQuestions() )
{
alert("Please answer at least half of the questions.");
return false;
}
So totalCompletedAnswers will return false if all the answers are not completed not the number of questions answered.
In checkForm the the following will evaluate to true: false < 7
See: http://jsfiddle.net/5mURZ/
Have a look at these two articles for more information on truthiness/falsiness in javascript:
http://11heavens.com/falsy-and-truthy-in-javascript
http://www.sitepoint.com/javascript-truthy-falsy/
UPDATE
Upon closer inspection you have a scoping issue. All your variables have a global scope. This will cause the most issues with the variable i. Declaring the variable with the var key word will restrict the scope of the variable to the function. It is best practice in javascript to delvare all variable with the var keyword to explicitly declare the scope of the variable.
Working Fiddle: http://jsfiddle.net/Dr5Hx/1/
Article on scoping: http://coding.smashingmagazine.com/2009/08/01/what-you-need-to-know-about-javascript-scope/
Update 2
For a completely different approach, try the magic of jQuery. This approach relies on wrapping the answers in some kind of container. In this case a div. This is required as elements such as check boxes and radio buttons would be multiple elements, but each set should only be counted once.
//The selector below finds DOM elements with a name beginning with "answer"
var answers = $("[name^='answer']"); //'Cache' answers
var answerDivs = $("div").has("[name^='answer']"); //'Cache' answer divs
var totalAnswers = answerDivs.length; //'Cache' number of answers
$("#checkIt").click(function(){ //Add a click listener to the button
var numAnswered = $(answerDivs).filter(function(){ //Filter our answer divs to answered question
var answer = $(this).find("[name^='answer']"); //Get the answer element(s) in the div
var textCheck = $(answer).is("input:text") && $(answer).val() != ''; //Check For Text Value
var selCheck = $(answer).is("select") && $(answer).val() != ''; //Check for selected
var radioCheck = $(answer).is(":checked"); // Check for Checked, WOrks for radio & checkbox
//console.log($(answer).attr("name") + " " + textCheck + " " + selCheck + " " + radioCheck)
return (textCheck || selCheck || radioCheck); //End of the filter
}).length;
if(numAnswered < (totalAnswers/2))
{
alert("Please answer atleast half the questions");
return false;
}
alert("We're good to go");
return true;
});
Just make sure to wrap the above in $(document).ready();
http://jsfiddle.net/Dr5Hx/3/

Related

JavaScript -- Validating a Certain Number of Inputs

I have 8 form inputs that are asking for either 8 half-day activity dates or, 4 fullday dates.
I collected all of the input values and put them into an array, and to test the collection process, wrote the following function that just says if ALL the inputs are empty, keep a button disabled and if ALL are full, enable the button.
function checkMeetings()
{
for(var i = 0; i < meetings.length; i++)
{
if(meetings[i] === "" || meetings[i] === null)
{
meetingsCanSubmit = false;
}
else
{
meetingsCanSubmit = true;
}
}
}
checkMeetings();
That test worked fine.
What I'd like to do is create a counter that counts the number of input boxes that have been filled in and when it gets to at >= 4 enable the button. (In reality it won't enable the button it's going to run a secondary function but for the purposes of this example I'm keeping it simple.)
Since the for loop is counting via the i++ anyways, I tried something to the effect of
if(meetings[i] <= 4) do the following, but that doesn't seem to be doing the trick. Should I be setting up a second counter within my if-statement?
You can use Array.prototype.filter(), check the .length of resulting array
var meetingsCanSubmit = meetings.filter(function(input) {
return input !== "" && input != null
}).length >= 4;
if (meetingsCanSubmit) {
// do stuff
}

GridView Validation is not working properly in JavaScript

I want to validate on button click that at least one of the rows must be edited and updated in JavaScript.
So I wrote the below code for validation
function checkGridValidate() {
var StrPriError = "";
var grdCount = GrdProspective1.Rows.length;
for (var i = 0; i < grdCount; i++) {
if (GrdProspective1.Rows[0].Cells[5].Value == "" || GrdProspective1.Rows[0].Cells[7].Value == "") {
StrPriError += "Kindly edit atleast one row \n";
}
if (StrPriError != "") {
alert(StrPriError);
return false;
}
else {
return true;
}
}
}
What happening here is, when I update the first row and submit it is not giving any alert that's perfect, but when I update the second row it still asks me Kindly edit at least one row.
I don't know what's going wrong here.
Have a look the js fiddle for the same
Currently, the validation is limited to only check the top row for two reasons:
.Rows[0] will always inspect the top row, despite the for loop.
This should make use of i as it increments through the collection:
if (GrdProspective1.Rows[i].Cells[5].Value == "" ||
The last if..else, by returning in either case, will interrupt the loop. The return statements here have a similar effect to break statements, with regards to the loop.
So, unless you want the loop to be interrupted, they should be moved out the loop:
for (var i = 0; i < grdCount; i++) {
if (...) {
// ...
}
}
if (StrPriError != "") {
alert(StrPriError);
return false;
}
else {
return true;
}
Though, fixing those should reveal a different issue – the function is checking that every row has been edited rather than one-or-more.
If, for example, there are 5 rows and you fill in both fields in 2 of the rows, the remaining 3 rows will match the condition and append the error message.
Inverting the condition, so you're searching for a row that's filled in and remembering whether you have, should resolve this.
function checkGridValidate() {
// assume invalid until found otherwise
var anyEdited = false;
var grdCount = GrdProspective1.Rows.length;
for (var i = 0; i < grdCount; i++) {
var cells = GrdProspective1.Rows[i].Cells;
// verify that both fields were given a value
if (cells[5].Value !== "" && cells[7].Value !== "") {
anyEdited = true; // remember that you've found an edited row
break; // and, no need to keep looking for more
}
}
// alert only if no rows were filled out
if (!anyEdited) {
alert("Kindly edit at least one row.");
}
return anyEdited;
}

Select at least one option in HTML

Situation: I want to create a simple code whereby users must select at least one extension to proceed. Users should select at least 1 or more extension, else an alert message will appear.
Problem: The problem is, if there shall be only 1 extension available for selection, whether it is selected or not, the alert message will appear disallowing the registration to complete.
//Select atleast one extension
var arrCheckboxes = document.checkForm.elements["product"];
var checkCount = 0;
for (var i = 0; i < arrCheckboxes.length; i++) {
checkCount += (arrCheckboxes[i].checked) ? 1 : 0;
}
if (checkCount > 0){
return true;
} else {
alert("Select at least one Extension.");
return false;
}
It is a legacy from the very early days of browsers that if there is only one form control with a name of product, then:
document.checkForm.elements["product"];
will return a reference to that control, not a collection which you seem to expect. Such controls do not have a length property by default so:
arrCheckboxes.length
returns undefined and
i < arrCheckboxes.length
is false so the loop is never entered.
To fix that, use querySelectorAll which always returns a collection:
var arrCheckboxes = document.checkForm.querySelectorAll('[name=product]');
Supported in IE 8+ and everywhere else. A simpler version of your code (assuming it's in the body of a function):
var arrCheckboxes = document.checkForm.querySelectorAll('[name=product]');
for (var i = 0; i < arrCheckboxes.length; i++) {
if (arrCheckboxes[i].checked) return true;
}
alert("Select at least one Extension.");
return false;

Store score in a variable after an event

Desirable result: After the user choose an answer, I want to modify score variable in:
score += 1 if the answer is right either not changing at all if the answer is wrong.
Current result: For every choice user is making, the score remains the same: 0.
First, I store the paragraph that will be changed in question_paragraph and the button that will be clicked by user in next_button. Also, I stored the value(I put the attribute value on every input using the array notation - 0 first, 1 second etc.) in user_answer.
var question_paragraph = document.getElementById('question');
var next_button = document.getElementById('next');
var i = 0;
var user_answer = getCheckedValue(document.getElementsByName('choice'));
var y = 0;
var score = 0;
The getCheckedValue function will return the value attribute of my input if exists.
function getCheckedValue(radioObj) {
var radioLength = radioObj.length;
for(var z = 0; z < radioLength; z++) {
if(radioObj[z].checked) {
return radioObj[z].value;
}
}
return "Error!";
}
Here is the problem. The function works fine, except the isolated area. allQuestion is my object where I stored the questions, the possible answers and the right answer, correctAnswer(I don't included it here but works correctly). I put a conditional statement to increase y and code>score with one if the allQuestions[y].correctAnswer is qual with the value of the user_choice.
function changeQuestion() {
//PROBLEM
if(allQuestions[y].correctAnswer == user_answer){
score += 1;
y++;
} else{y++;}
//PROBLEM
i = (i < allQuestions.length) ? (i + 1) : 0;
if (i == allQuestions.length) {
i = 0;
return question_paragraph.replaceChild(document.createTextNode(allQuestions[0].question), question_paragraph.firstChild);
}
var newNode = document.createTextNode(allQuestions[i].question);
console.log(score);
return question_paragraph.replaceChild(newNode, question_paragraph.firstChild);
}
Finnaly, I called the addHandler function.
function addHandler(name, type, handler){
if (name.addEventListener){
name.addEventListener(type, handler, false);
} else if (name.attachEvent){
name.attachEvent("on" + type, handler);
} else {
name["on" + type] = handler;
}
}
addHandler(next_button, 'click', changeQuestion);
Well, something just appears to be funny here so far. First of all, I don't see any initialization to the variable y. If y is a global variable that is retaining its value, then maybe there is an issue with your object: allQuestions{}. Could you provide the code for building your object allQuestions{}? Without it, I don't think that I could fully answer this question, but I believe that is where your problem lies.
Oops, this was supposed to be a comment, not an answer, sorry...

How to use JavaScript to Require a Ratio of Completed Fields in a Form

I'm looking for a way to use JavaScript to require a specific ratio of fields in a form to be complete. So if I have six fields and the user has to complete any 2/6 to submit. If not then they receive an error. (The form will actually have a few different groups like this in it, so I have to be able to identify specific fields for the ratio.)
After some more research I've found something close, and realize I can count the number of a class. How would I change this to say if number of checked boxes is greater than or equal to 2, return true?
document.getElementById("test").onclick = function() {
isCountCheck("Check something");
};
function isCountCheck(helperMsg) {
var i, len, inputs = document.form1.getElementsByClassName("checkbox");
for (i = 0, len = inputs.length; i < len; i++) {
if (inputs[i].type === "checkbox" && inputs[i].checked) return true;
}
alert(helperMsg);
return false;
}
UPDATE:
My final jQuery ended up like this.
function isCountCheck(){
if($("input[class=crit1]:checked").length >= 4)
return false;
alert("Check a box");
return true;
}
Using jQuery
var numberOfInputsCompleted = 0;
var allInputs = $(":input"); // returns all input fields on the document
var numberOfInputs = allInputs.length
allInputs.each(function () {
if($(this).val() != '') {
numberOfInputsCompleted = numberOfInputsCompleted + 1;
}
});
numberOfInputsCompleted would give fields completed and numberOfInputs would total number of input fields on the form. Hope this helps
The first thing that comes to my mind: create a function that counts filled fields and returns true if the number of filled fields is enough (false otherwise). Then add it to the form as an "onsubmit" function. When the submit button is clicked the function is executed and, depending on what the function returns (true or false), the form is submitted or not.
More info about javascript form validation: http://www.w3schools.com/js/js_form_validation.asp

Categories