Javascript for loop behaving as though 2=21 - javascript

I've found a lot of discussion about javascript validation functions for forms but can't find anyone running into this particular problem.
In the code below, even though there are 21 values in the array 'fields[]', the for loop ends after 2 iterations. The last alert it pops reads "1 < 21" - it's as though it thinks 2 is not less than 21.
I thought it might be a data type error but can't figure it out. Thanks to anyone who can see it.
var fields = new Array;
var fields = [
document.forms["survey"]["Q1Age"].value,
document.forms["survey"]["Q2Gender"].value,
document.forms["survey"]["Q3Education"].value,
document.forms["survey"]["Q4Field"].value,
document.forms["survey"]["Q6Other"].value,
document.forms["survey"]["Q7Edited"].value,
document.forms["survey"]["UserAccount"].value,
document.forms["survey"]["Whole"].value,
document.forms["survey"]["Sections"].value,
document.forms["survey"]["Images"].value,
document.forms["survey"]["Keywords"].value,
document.forms["survey"]["writing"].value,
document.forms["survey"]["trustworthy"].value,
document.forms["survey"]["accuracy"].value,
document.forms["survey"]["bias"].value,
document.forms["survey"]["info"].value,
document.forms["survey"]["Viz1"].value,
document.forms["survey"]["Viz2"].value,
document.forms["survey"]["VizDescription"].value,
document.forms["survey"]["VizOver"].value,
document.forms["survey"]["submit2"].value
];
var err = 0;
//Start Validation Loop
for(var i = 0; i < fields.length; i++) {
alert(i + " < " + fields.length); //test how many iterations
//Check Fields in Array to Make Sure they are not Empty
if(fields[i].value == "" || fields[i].value == "Select One") {
err++;
}
}
if(err === 0) {
//Submit Form
//document.survey.submit();
return true;
} else {
//If there are errors, return false and alert the user
alert("Please fill out all of the fields.");
return false;
}
}

Since you are getting the input's value when you are creating the array your array elements are already strings, so in your if statement you are trying to get property value from a string, which is probably causing the script to end cause it is trying to access an undefined property
Your if statement should be this.
if(fields[i] == "" || fields[i] == "Select One") {
err++;
}

Related

How to write in one more condition inside input validation?

New to Javascript. My function is muddled and I would like some guidance on how to execute this properly.
This function shall display a message (from the msg[]) contingent on the status of an input field. Currently, there is only one condition for an input to be considered erroneous - if the input field is empty. I would like to add another condition (if an input is NaN, display appropriate message from another array called msg2[]) but I am lost on how to write it in. I know I could just simply utilize HTML5's 'required' attribute or input type="number" however, I would like to hard code this function for my personal gain.
How can I make the function choose between 2 conditions and display appropriate message from corresponding array?
function validateForm(someForm) {
document.getElementById('errorMsg').innerHTML = "";
var allInputs = document.getElementById("studentform").getElementsByTagName("input");
for (var i = 0; i < allInputs.length; i++) {
if (allInputs[i].name != "final-average-result" && allInputs[i].name != "final-letter-grade-result") {
if (allInputs[i].value == "") {
document.getElementById('errorMsg').innerHTML = msg[i];
if (currentField) {
currentField.style.border = "2px solid #CCC";
}
allInputs[i].style.border = "2px dotted #F00";
currentField = allInputs[i];
allInputs[i].onclick = function () {
this.style.border = "2px dashed #CCC";
}
return;
}
}
} // end for
} // end validateForm
var msg = ["Name should not be empty", "This field should not be empty",
"This 3rd field should not be empty", "The last field should not be empty."];
var msg2 = ["Invalid input", "error message here",......."]
Us if else and isNaN() function
function validateForm(someForm) {
document.getElementById('errorMsg').innerHTML = "";
var allInputs =
document.getElementById("studentform").getElementsByTagName("input");
for (var i = 0; i < allInputs.length; i++) {
if (allInputs[i].name != "final-average-result" && allInputs[i].name != "final-
letter-grade-result") {
if (allInputs[i].value == "") {
document.getElementById('errorMsg').innerHTML = msg[i];
if (currentField) {
currentField.style.border = "2px solid #CCC";
}
allInputs[i].style.border = "2px dotted #F00";
currentField = allInputs[i];
allInputs[i].onclick = function () {
this.style.border = "2px dashed #CCC";
}
return;
} else if(isNaN(allInputs[i].value)) {
// display error
}
}
} // end for
} // end validateForm
var msg = ["Name should not be empty", "This field should not be empty",
"This 3rd field should not be empty", "The last field should not be empty."];
var msg2 = ["Invalid input", "error message here",......."]
There are lots of different possibilites to consider when performing input validation. There are plugins, and frameworks etc that help you, where you have gone down a fairly manual brick and mortar approach. But thats beside the point...
I find that there are problems with your logic, and there is where you should start to refactor your solution. You are using an array implicitly to hold the error messages for all imput fields. So that first input has a custom error message in the first slot in msg array. This seems to be extremely brittle and will break at some point, you already have a filter which removes two fields from this order, are you sure you compensate for that? Also, you seem to stop at first invalid field?
When trying to validate type of value for msg2, and if you want to support differnet kind of values and validations, this logic won't work. You need to be able to use different requirements for different fields, and perhaps several validation criterias for one field...
You simply need to work out another strategy. One close to your attempt would be to structure your fields in a object by field name or id, and then have a corresponding object for validation, where fields represent validation error for a specific type of error.
var inputFieldValidationErrorMap = {
'first-field-name': {
empty: 'Name should not be empty',
wordchars: 'Name must be only valid letter chars'
},
'second-field-name': {
empty: 'This field should not be empty',
nan: 'This field must contain only numbers'
}
}
To use this in your current code, you'd write something like
function validateForm(someForm) {
document.getElementById('errorMsg').innerHTML = "";
var allInputs = document.getElementById("studentform").getElementsByTagName("input");
for (var i = 0; i < allInputs.length; i++) {
if (allInputs[i].name != "final-average-result" && allInputs[i].name != "final-letter-grade-result") {
var name = allInputs[i].name;
var errorElement = document.getElementById('errorMsg');
var validation = inputFieldValidationErrorMap[name];
if (allInputs[i].value === "" && 'empty' in validation) {
errorElement.innerHTML = validation.empty;
return;
} else if(isNaN(allInputs[i].value) && 'nan' in validation) {
errorElement.innerHTML = validation.nan;
return;
}
//... Go on here for every type of validation you support
}
} // end for
} // end validateForm
Further improvements
This solution is by no means perfect, and it has its limitations as well. You could also use some data attribute on your input fields to contain your validation requirements, and you should combine your solution with setting correct input types etc, using native html attirbutes for better usability. You should allow each input to display its own error, and run validation passes through all fields in the form so that all errors are current. There are frameworks and plugins to consider as well, to be sure your not running into trouble.
You can use an else if statement like
if (input != condition ){}
else if (input != condition ){}
The statement if (allInputs[i].name != "final-average-result" && allInputs[i].name != "final-letter-grade-result") is also incorrect. You should use || operator instead of &&. allInputs[i].name will not be equal to 2 strings at same time

token error when checking if a word exist with for loop and indexOf

I'm trying to check if there the word "#gmail.com" in the user input when the user type anything and if the word is not there, then repeat the question until the user includes the word "#gmail.com" but I'm getting token error in the console with unexpected ), I just started learning loops but wanted to try this idea with only for loops and if statements.
for (var userInput = prompt("enter your email"); userInput.indexOf("#gmail.com") === -1); {
var userInput = prompt("enter your email");
if (userInput.indexOf("#gmail.com") !== -1) {
alert("Welcome");
}
}
You're for-loop syntax is wrong. It has to have 3 statements in braces, like this:
for(var i = 0; i < 2; i++) {
//Do something
}
The first statement is excecuted once when the loop starts.
The second statement checks if the code inside the loop should be excecuted.
And the third statement gets excecuted after each loop.
So in your case it would be:
//We ignore the last statement, but have to keep the semicolon!
for (var userInput = prompt("enter your email"); userInput && userInput.indexOf("#gmail.com") === -1; ) {
userInput = prompt("enter your email");
if (userInput && userInput.indexOf("#gmail.com") !== -1) {
alert("Welcome");
}
}
This would be looping with a for-loop like you did, but of course FĂ©lix Brunets answer is more elegant for this purpose.
I hope this helps. -Minding
as I understood what you wanted to do :
var userInput;
do {
userInput = prompt("enter your email");
} while(userInput.indexOf("#gmail.com") === -1)
alert("Welcome");
It's may not be the best way to do it. With a script like that, you do not check where the "#gmail.com" is, you cannot stop or cancel, etc.

if else preventing loop for passing through object

I am having trouble returning a statement when my RegExp finds no matches :
function ai(message) {
if (username.length < 3) {
username = message;
send_message("Oh, well hello " + username + ", My name is Donald J Trump and i'm a big boy");
} else {
for (i = 0; i <= botChat.length; i++) {
var re = new RegExp(botChat[i][0], "i");
if (re.test(message)) {
var length = botChat[i].length - 1;
var index = Math.ceil(length * Math.random());
var reply = botChat[i][index];
send_message(reply);
}
}
}
}
When I enter a phrase it can correctly match the first line in an array as per the for loop. The issue I'm having is when I try to add an else statement it ceases to loop through my array properly.
I have tried :
else if (re.test(message) === false) {
send_message("i can't be expected to know everything");
}
But it doesn't work, it prevents the loop from looping past botChat[0][0].
I've also tried :
if (send_message().val() == "") {
// ...
}
But every time my code no longer works. Is there a method of adding something to my array that says 'if you don't find a match above, choose this'?
Or just a way of working my code so that the if/else works?
attached is the codepen.
I checked your codepen and the lines 190 and 194 console.log(send_message().val()); seems to be breaking the loop because those lines are throwing an exception since send_message() returns undefined and undefined does not have the .val() method.
Your regular expressions are working fine. I recommend not creating new RegExp objects every iteration, instead, use the one defined in the array if (botChat[i][0].test(message)), the overhead will be less.

Populate a prompt with elements of an array and number them off

(Stack Overflow doesn't have a tag for 'prompt' so I have used alert as I am guessing it is similar enough to attract the right answerers.)
Hello,
I am currently making a JavaScript-based game for an assignment at university. I am usually pretty good with problem solving but have been stumped by this issue.
To explain, I have an array which names the possible armour slots the player can pick. In any order these can be picked, and each time the choice gets pushed to a second array which handles what has already been picked (and in what order) and that item gets spliced from the original array. There is a while loop which runs through until all 3 have been picked.
var armourSlotToPick = ["Head", "Chest", "Legs"],
armourSlotPicked = [],
armourLoop = 1,
indexArmour = 0;
function numInArray() {
indexArmour++;
return (indexArmour + ". " + armourSlotToPick[indexArmour - 1] + "\n");
}
function armour() {
while (armourLoop < 4) {
var armourPick = prompt("Pick an armour slot to generate an item for:\n" + armourSlotToPick.forEach(numInArray));
if (armourPick == 1) {
armourSlotPicked.push(armourSlotToPick[0]);
armourSlotToPick.splice(0,1);
} else if (armourPick == 2) {
armourSlotPicked.push(armourSlotToPick[1]);
armourSlotToPick.splice(1,1);
} else if (armourPick == 3) {
armourSlotPicked.push(armourSlotToPick[2]);
armourSlotToPick.splice(2,1);
} else {
alert("Invalid choice, you suck");
break;
}
armourLoop++;
}
}
I know it probably wouldn't be possible to do the whole return in numInArray() to the prompt, but it shows some working.
Now the problem: I got it working so that each item in the array was numbered (var armourSlotToPick = ["1. Head", "2. Chest", "3. Legs"],) but as you could see, if the player chose 2, then the next time it would show "1. Head (new line) 3. Legs" and when the player chooses 3, a problem would occur, as they were really meant to choose 2. How is it possible to number the items in the array, in a prompt?
I'm possibly over thinking this but I have suffered for a few hours now.
I thank you in advance for any insight you may have,
Daniel.
EDIT: Solved.
Below is the end result, a slight variation from the edited answer from Jonathan Brooks.
var armourSlotToPick = [null, "Head", "Chest", "Legs"]
var armourSlotPicked = [null];
var armourLoop = 1;
function armour() {
while (armourLoop < 4) {
var message = "Pick an armour slot to generate an item for:\n";
for (var i = 0; i < armourSlotToPick.length; i++) {
if (armourSlotToPick[i] !== null) {
message += "" + i + ". " + armourSlotToPick[i] + "\n";
}
}
var armourPick = prompt(message);
if (armourPick > armourSlotToPick.length-1 || armourPick < 1) {
alert("Invalid choice, you suck");
} else {
var insert = armourSlotToPick.splice(armourPick, 1);
armourSlotPicked.push(insert);
}
armourLoop++;
}
armourSlotPicked.splice(0,1);
}
armour();
alert(armourSlotPicked.join("\n"));
I thank all that have contributed to this discussion and the end result, and I hope this is a good example for future problems people may have similar to this.
Check out my fiddle, I think I have a working solution.
What you really want to be using are Object Literals with your own indexing (starting from 1) - if it were me, I would create my own way to iterate over this custom indexing by adding a method to the Object's prototype, but I digress.
You're overcomplicating your code by using a while loop, and that large bulk of if statements is unnecessary: instead, all you need is some basic validation on the input and then you can just trust whatever input passes this validation. That is demonstrated here:
if ( armourPick > armourSlotToPick.length || armourPick < 1 ) {
alert("Invalid choice, you suck");
}
else {
armourSlotPicked.push( armourSlotToPick[armourPick-1] )
alert (armourSlotPicked[armourSlotPicked.length-1].value);
}
Read my code carefully, and you should get a better understanding of how to deal with certain issues.
EDIT:
As per your request, I think I have a solution that suits your needs. Basically all you have to do to have the arrays "start" at an index of 1 is to fill the zeroth element with a null value, like so:
var armourSlotToPick = [null, "Head", "Chest", "Legs"]
var armourSlotPicked = [null];
You just have to remember to take this null object into account in your code, for example:
if (armourSlotToPick[i] !== null) {
message += "" + i + "\n";
}
The indices will update automatically. See this updated fiddle for more details.
use structures / objects as content in the array, instead of just values.
the basic concept:
armourSlotPicked.push({ "key": 1, "value":armourSlotToPick[1]})
alert("value: " + armourSlotPicked[0].value)
alert("key: " + armourSlotPicked[0].key)
edit: responding to comments can take some space.
IMHO a prompt is the completely wrong tool for this, since most browsers would ask the user permission to prevent multiple popups, and since a promt can only return 1 piece of information, you can only ask for 1 thing per popup. Instead you ought to use a div element, with checkboxes for each information..
That being said it can easily be used in a promt.
The prompt is just a built in function, that takes a string as an argument (which is shown as text in the popup) and returns a string with the users input.
what does the magic for you is in fact this:
array.foreach(): The forEach() method executes a provided function once per array element.
in your case that means it calls a function that returns a string for each element in the array, and concatenates the strings.
in the old days you would have written this:
var messageText= "Pick an armour slot to generate an item for:\n"
for(var i = 1; i < armourSlotToPick.length; i++){
messageText += i + ". " + armourSlotToPick[i- 1] + "\n";
}
var armourPick = prompt(messageText);
but in this modern age, you define a printing function, and use it to generate the loop:
function numInArray() {
indexArmour++;
return (indexArmour + ". " + armourSlotToPick[indexArmour - 1] + "\n");
}
//more code before we get to where the function is used....
indexArmour = 0;
var messageText = "Pick an armour slot to generate an item for:\n" + armourSlotToPick.forEach(numInArray);
var armourPick = prompt(messageText);
or in a single line as in your code:
indexArmour = 0; //you forgot this - otherwise the list will only be complete once?
var armourPick = prompt("Pick an armour slot to generate an item for:\n" + armourSlotToPick.forEach(numInArray));
It produces the same output, because it does the same thing, its just written very differently!
If the array holds "object literals" instead of simply values, as I suggest, the old fashioned code would look something like this:
function contains(a, value) {
try{
for (var i = 0; i < a.length; i++) {
if (a[i].value == value) {
return true;
}
}
}
catch(err) {
// do nothing
};
return false;
}
and later..
for(var j = 0; j < 4; j++){
for(var i = 0; i < Math.min(armourSlotToPick.length); i++){
if( contains(armourSlotPicked, armourSlotToPick[i- 1]) )
continue;
var messageText = "Generate an item for armour in slot: " + i + "\n"
messageText += armourSlotToPick[i- 1] + "\n";
}
var armourPick = prompt(messageText);
if (armourPick > 0 && armourPick < armourSlotToPick.length) {
armourSlotPicked.push({"key":j, "value":armourSlotToPick[armourPick]);
}
...
}
//now we have an array that holds information about when what was picked..
or something along those lines.. this is bt.w completely untested, it's just for illustration
You want to use the array index to number your items. Since your numbers are one-based and the index is zero-based, you will need to convert between the two when outputting and interpreting the response.
This approach will also allow you to eliminate all but two of the cases in your if-else statement.

Repetitive result in Javascript

I am currently working with some test codes in Javascript. When I inserted the ..else {} in a IF statement within a for..loop, procedures under else{} should not be run if the statement is TRUE, but it is not happening. The output is always displays the message "No place logged" even the statement is TRUE.
A beginner in Javascript here. :-)
this is the sample code.
function forLoops() {
for (var x = 0; x < places.length; x++) {
if(userInput === places[x]) {
console.log("Your place input " + userInput + " is on our database.");
} else {
console.log("No place logged!");
}
}
}
you are using === and not == which in javascript means equal and no type conversion.
so if userInput is NOT a number but maybe a string of a number "6" insead of 6, than its not equal.
check your function with ==
Solved it!
I should use == not === when declaring variables.
I realized it when trying and testing my code.
Answers above supported my answer.
Here userInput is undefined according to your provided code
Another thing is that
if you use === it won't use conversion during checking. it is strict comparing but if you use == then it will done conversion and then comapare with each other.
try like this
function forLoops(userInput) {
for (var x = 0; x < places.length; x++) {
if(userInput === places[x]) {
console.log("Your place input " + userInput + " is on our database.");
} else {
console.log("No place logged!");
}
}
}
pass user input to foorloop during calling
When using the === , you have to make sure that both operands are of the same type, in your case 'userInput' and all elements contained in your array 'places'. Try with == as suggested in the comments.

Categories

Resources