stuck with Javascript infinite while loop - javascript

My apologies for the n00b question, I've tried looking through infinite loop related issues but they're way more complex:
var replay = 1;
while (replay = 1) {
replay = prompt("Yes(1) or No(0) ?");
}
How come this is an infinite loop?
I thought this while loop would only continue iterating while the replay variable has a value of 1.
However it doesn't stop even when user input is 0, or anything else for that matter.
Thanks in advance for any of your input!

You're doing an assignment instead of a comparison.
Change:
while (replay = 1) { // Will always have a value of 1
to:
while (replay == 1) { // Will have a value of true or false

Use == instead of = in the while part.

You are assigning not checking in (replay = 1)
You need double equal signs ==, or better yet triple equal signs === which will also check the equality in types of the operands.
Besides, your code can be changed to this (preview: http://jsfiddle.net/nabil_kadimi/RfdA5/):
var replay;
while ((replay = window.prompt("Yes(1) or No(0) ?")) === '1') {
/* player wants to replay */;
}
Or even better (preview: http://jsfiddle.net/nabil_kadimi/pdV4M/):
var replay;
while (replay = window.confirm("Replay?")) {
/* player wants to replay */;
}

You need to use == (equality) instead of = (assignment) in your while loop
while(replay == 1) {
//code
}
JavaScript is doing what it is supposed to. You are reassigning the value of 1 to replay every time the loop iterates. You really want to check if replay is equal to one before proceeding.

You want to use the === comparison operator instead of the = assignment operator in the while loop.
Also, since prompt returns a string, you should compare against a string:
var replay = "1";
while (replay === "1") {
replay = prompt("Yes(1) or No(0) ?");
}

Related

Is there a way to discontinue a forEach loop once you reach a certain key:value pair in the array?

I'm still very new to Javascript and software development in general as this is my first job, and right now I am debugging a critical defect related to validation.
I have a scenario where I have an array, and within that array each product has an attribute labeled Unit Volume with a code of ASC_Sales_Volume.
The current defect is that when a user configures more than one product, but leaves one with a unit volume of zero, the user is still allowed to navigate forward to the next page despite there being a validation check in place to prevent this. The condition that would block the user from moving forward is if $scope.bpTree.response.errorCheckVolume = true.
WIth what is currently written by the former dev, the forEach loop keeps changing the $scope.bpTree.response.errorCheckVolume back to false when the user clicks on the button to fire the functions.
The Next button itself is an OOTB component that I cannot modify directly.
What would be the next best step in troubleshooting this? Basically, when the forEach evaluates a product with a Unit Volume value of 0, the $scope.bpTree.response.errorCheckVolume should always equal true regardless of subsequent Unit Volume values, until the user changes the Unit Volume value for that particular product and then clicks the Next button and the logic fires again. If the error records (as in, any product in the array with a Unit Volume of 0) are greater than zero, then errorCheckVolume should always evaluate to true and the user should be blocked from progressing.
Would I use something similar to Array.prototype.some()? I've just been staring at my screen for hours trying different things to no avail.
Here is the code snippet:
function validateAllPlansUnitVolume(triggeredFromNextBtn) {
var coveragesData = $scope.sortedCoverages[$scope.childProduct.instanceKey || $scope.childProduct.productName || $scope.childProduct.Name],
errorRecords = checkForInvalidPlans(coveragesData, triggeredFromNextBtn);
if(errorRecords > 0) {
$scope.bpTree.response.errorCheckVolume = true;
}
else {
$scope.bpTree.response.errorCheckVolume = false;
}
}
function checkForInvalidPlans(coveragesData, triggeredFromNextBtn){
if(!!coveragesData && coveragesData.length) {
coveragesData.forEach(function(product){
if(!!product.attributeCategories){
unitVolumeAttrNodes = product.attributeCategories.records[0].productAttributes.records.filter((ele) => ele.code == "ASC_Sales_Volume");
if(!!unitVolumeAttrNodes && unitVolumeAttrNodes.length){
unitVolumeAttrNodes.forEach(function(attrNode){
if(unitVolumeAttrNodes[0].userValues === 0){
$scope.bpTree.response.errorCheckVolume = true;
product.unitVolumeErr = true;
product.unitVolumeErrMsg = "Unit Volume cannot be zero. Please update before proceeding to the next screen";
}
else {
product.unitVolumeErrMsg = "";
product.unitVolumeErr = false;
$scope.bpTree.response.errorCheckVolume = false;
}
});
}
}
});
return coveragesData.filter((ele) => ele.unitVolumeErr).length;
}
return 0;
}
i will suggest you should use Array.prototype.some() for this purpose. its not good practice to use foreach loop then break it on condition.
Js has different array's method for different work. i think for different requirement they created built methods otherwise we can use one method for all work,
Visit this page select array method that fit in your requirement
You can't do that with .forEach, but you can with .some:
['a', 'b', 'c'].some((element, index) => {
console.log(element);
return element == 'b' || index == 1;
});
This code logs each element of the array, discontinuing the loop after it reaches 'b' or index 1.

Text Input Value sometimes does't change even though it thows no errors, and seems to work

So I have a simple program to change the value of an input field every time you blur it. It logs the already used values in an array, an I use that array to check if it's been used. It practically works as intended, but after a few tries it will return true and logs, yet the value wont change.
Updated Code:
var dftvalue = ['Freddy the Grocer', 'Jack the Fiddler', 'Cane the Sheep Herder', 'Arnold the Fish Monger', 'Luke the Car Salesman', 'Josh the Tailor', 'Carol the Baker', 'Tiara the Nacho Vendor', 'example#email.com', 'Your message here.'];
var logused = new Array(); //create new array to log the used indexs
function setdftvalue() {
var newval = dftvalue[Math.floor(Math.random() * 7)];
if (logused.indexOf(newval) == -1) {
this.value=newval;
logused.push(newval);
console.log(logused);
} else if (logused.indexOf(newval) >= 0) {
setdftvalue();
}
if (logused.length == 8) {
for (i=0; i<=7; i++){
logused.pop();
}
}
}
document.getElementById('formname').onblur=setdftvalue;
JSFIDDLE
https://jsfiddle.net/e5pdz37e/8/
Your approach is unnecessarily complicated. At a high level I would recommend an approach that's more like this:
function setdftvalue() {
if (index === (dftvalue.length - 1)) {
// Shuffle your names array
index = -1;
}
input.value = dftvalue[++index];
}
This way you won't need to use any recursion and make unnecessary function calls. And the only time you'll need to randomize is when you've used up all of your available names.
Here's a working example: http://jsfiddle.net/bvaughn/163mqdeL/
Original answer
After a few invocations, your function will fill up the logused Array, at which point calling it again will do nothing. Actually, worse than nothing - it will recursively call itself without end.

Iterating through an array until random value isn't equal to anything

First of all, I am very new to programming so apologies in advance.
This is what I am trying to do:
1) Generate a random value into a variable using
questionNr = Random.Range(0, nNodes);
2) Compare that variable to an array by iterating through all its values
for(var i=0; i<usedQuestionList.length(); i++){
if(questionNr == usedQuestionList[i]){
//stuff
}
}
3) If any value of the array is equal to said variable's value, start from the beginning by generating a new random value and loop through the array again. The only way to pass/end the loop is when the random value is NOT equal to any of the values in the array.
The problem is that if I do this simple for loop, there's no way for me to go back and do everything again when the conditions are not met.
I'm pretty sure I'm just approaching the logic wrong and there's a simple way to do this that hasn't occurred to me, that's why I'm not adding any of the code from my failed for and while loop attempts. Any help appreciated, thanks!
You can set a flag that you can check after the loop has finished, maybe something like this:
//A function that will take a number and check against the array
var loopRandomNumber = function(number){
//A flag to be used if match is found
var foundMatch = false;
//Your simple loop
for(var i=0; i<usedQuestionList.length(); i++){
//Checking if match
if(number == usedQuestionList[i]){
foundMatch = true; //Match found
break; // Jumps out of the for-loop to be a little faster
}
}
//Calling this function again with a new random number if match found
if(foundMatch){
loopRandomNumber(Random.Range(0, nNodes));
} else {
//Handle your condition for if no match was found here
}
}
loopRandomNumber(Random.Range(0, nNodes));

JavaScript Help (Loops and Arrays in Particular)

So I am doing an assignment for a required javascript class and am stuck on a couple of parts specifically. We are supposed to create a guessing game with an array where we prompt the user to guess names and if they match anything in the array to tally it up as points.
Anyway here is the main code, the part that I am stuck on is figuring out how to loop the code so when the user is prompted 3 times for a guess and each guess is taken into account
var sportsArray = ["Football","Basketball","Rollerblading","Hiking","Biking","Swimming"];
var name = prompt("Please enter your name.", "Enter Here");
var arrayGuess = prompt("Guess a sport.", "Enter Here");
var counter;
for (counter = 0; counter < sportsArray.length; counter++) {
if (arrayGuess === "Football"||"Basketball"||"Rollerblading"||"Hiking"||"Biking"||"Swimming"){
alert("Good Job");
} else {
arrayGuess;
}
}
So the goal is to prompt the user to guess a part of the original array and if they do let them know that, but if they don't take points away and make them guess again until they have guessed 3 times.
Anyway if someone could lend a hand it would be appreciated.
You cannot simultaneously compare one item to a whole bunch of things like this:
if (arrayGuess === "Football"||"Basketball"||"Rollerblading"||"Hiking"||"Biking"||"Swimming")
Instead, you have to compare it to each individual item:
if (arrayGuess === "Football"||
arrayGuess === "Basketball"||
arrayGuess === "Rollerblading"||
arrayGuess === "Hiking"||
arrayGuess === "Biking"||
arrayGuess === "Swimming")
Or, there are more effective ways to compare to multiple items such as:
if (" Football Basketball Rollerblading Hiking Biking Swimming ".indexOf(" " + arrayGuess + " ") !== -1)
Or, using an array:
if (["Football","Basketball","Rollerblading","Hiking","Biking","Swimming"].indexOf(arrayGuess) !== -1)
Or, if this comparison happened a lot, you'd build an object ahead of time and use it for a lookup:
var items = {"Football":true,"Basketball":true,"Rollerblading":true,"Hiking":true,"Biking":true,"Swimming":true};
if (items[arrayGuess] === true)
If you want to compare without regards for proper case, then you can lowercase what the user entered and compare that to lower case test values:
var items = {"football":true,"basketball":true,"rollerblading":true,"hiking":true,"biking":true,"swimming":true};
if (items[arrayGuess.toLowerCase()] === true)
FYI, it's also not clear why you're using a loop here at all. No loop is needed to prompt once and test against all the possible sports values.
If you have to cycle through an array with a loop, then you can do this:
var items = ["football","basketball","rollerblading","hiking","biking","swimming"];
var testVal = arrayGuess.toLowerCase();
var match = -1;
for (var i = 0; i < items.length; i++) {
if (testVal === items[i]) {
// found a match
match = i;
break;
}
}
if (match !== -1) {
// items[match] was the match
} else {
// no match
}
I see a couple of things wrong here, as was already mentioned, your comparison in the if statement needs to reference the variable each time it is compared. But additionally, since you are in a loop based on the length of your sportsArray variable, it would be better to not reference strings at all in the if statement, and instead do something more like the following:
if (arrayGuess === sportsArray[counter]) {
// Do stuff here
} else {
// Do other stuff here
}
Additionally, your else clause isn't going to behave quite like you are expecting it to. You are going to have to assign a new value to it, probably by way of another call to prompt. As of now you are only referencing the variable, which will do nothing. If you need to take three guesses, I would add an 'else if' clause into the mix where you get a new value for the variable, an let the else clause display a score and break out of the loop.
if (arrayGuess === sportsArray[counter]) {
// Add to the score
} else if (counter < 2) {
// We prompted for the first guess before the loop,
// so take the second and third here
arrayGuess = prompt("Guess a sport.", "Enter Here");
} else {
// Display score then break to exit the loop
break;
}

Strange results with javascript array.length function

I have piece of JavaScript code which cycles through form elements and builds an object.
I have a mixture of HTML input fields and ASP.NET input fields. ASP.NET changes the ID of the fields to the form xxxxx_yyyy_id, so I am attempting to use the split function to extract the original id.
// Iterate over all the text fields and build an object
$(':text').each(function () {
var tokens = this.id.split("_");
if (tokens.length = 3) {
// Assume this is a .net inputbox - extract the original id
inFormData[tokens[2]] = this.value;
} else {
inFormData[this.id] = this.value;
}
});
Stepping through the above code, the first id is ctl00_ContentPlaceHolderCol1_forenameField, so the tokens.length = 3 code is run.
On the second iteration, the id is forenameField2 so I would expect the tokens.length to be 1, but it is actually 3. The else statement is never run.
This could be something simple, but I cant work it out. If I inspect the tokens array it has only 1 element in on the second iteration. I have also tried setting the array.length to 0 after each iteration.
Any help appreciated.
Correct this:
== instead of =. === is more better
if (tokens.length == 3) {
// Assume this is a .net inputbox - extract the original id
inFormData[tokens[2]] = this.value;
} else {
inFormData[this.id] = this.value;
}
Change your = 3 to === 3
At the moment you're overwriting tokens.length every time.
NB: === is preferred to == because it's an exact equality check. The two-equals version will attempt to cast the two operands to the same type before comparison, which is 1. unnecessary, 2. inefficient, 3. sometimes error prone.
That is why you should always put the constant first when testing. If you forget a comparison sign it will throw an error:
if( 3 = tokens.length ) // throws an error
if( 3 == tokens.length ) // ok
if( 3 === tokens.length) // ok
from:
if (tokens.length = 3) {
to:
if (tokens.length == 3) {

Categories