Search code examples
javascriptloopsif-statementwhile-loopinfinite-loop

Why isn't my nested while loop in an if/else statement outputting correctly (infinite loop)?


I have two loops (a while and an if) embedded in an if/else statement.

I'm wanting to check if the user input is a number and if not, set a limit to how many times the user can try again (3 times) and alert the user when they have run out of repeats. If the user never enters in a number, return undefined.

Or if the user enters in a number, skip the check and return the number as an integer data type.

function monthlyBudget(count = 3) {
    const SPEND = prompt("How much is your typical spend (in GBP) on books in a month? ");
    
    // check if the input is not a number.
    if (isNaN(SPEND)) {

        while (count > 0) {
            alert("Hmmm... I'm not sure I understood. Please try again.");
            console.log("Spend input is not a number.");

            count--
            console.log(count)
            monthlyBudget(count);
        }

        // if SPEND is not a number and count = 0.
        if (count == 0) {
            alert("Oh no! We are unable to process your request, please try again later.");
            return undefined
        }
    } else {
        return Number(SPEND)
    }
}

But it seems like it goes through until count = 0 and it outputs the count = 0 alert, but then it goes back and immediately outputs "Hmmm... I'm not sure I understood. Please try again." and then back to "Oh no! We are unable to process your request, please try again later."

console.log shows once count gets to 0, it goes back up to 1 again before going back down to 0, so the alerts match what count is, but I'm not sure why this code is doing that?

Can anyone point out where I'm going wrong?

With my first try the if/else statement looked slightly different:

if (isNaN(SPEND)) {
        alert("Hmmm... I'm not sure I understood. Please try again.");
        console.log("Spend input is not a number.");
        monthlyBudget();
} else {
        return Number(SPEND);
}

but if the first input (or those following) was a string, no matter what the next input was, the function would only return the first string input.

I'm not sure why as there is no return for if (isNaN(SPEND)) and I'm not sure if this is still an issue with the code in the first block as I think I'm stuck in an infinite loop.


Solution

  • You tried to implement the loop by both a while loop and recursion. That is problematic. Moreover, when you have made the recursive call, you are ignoring the answer that this recursive call might return. You should return it and not loop again.

    So change this:

    monthlyBudget(count);
    

    to:

    return monthlyBudget(count);
    

    Now you also can replace that while with an if, since it is sure you will execute that return. There is no second iteration there. The repeating is implemented by recursive calls, not a while loop.

    NB: it is not good practice to ask user input via prompt and alert. Use HTML input controls for that.

    With iteration, no recursion

    Put the prompt call inside the loop, and exit the loop when the number is accepted (so it is the opposite if test). If the loop exits, it means all retries have been consumed without success, and it is time to display that final alert.

    Some remarks:

    • Don't use ALL CAPS for variables that take user input. It is common practice to reserve the use of ALL CAPS for constants defined in the code.

    • Separate all statements with semi-colon.

    I left in the prompt, and alert that apparently you were asked to use for this exercise:

    function monthlyBudget(count = 3) {
        while (count > 0) {
            let spend = prompt("How much is your typical spend (in GBP) on books in a month? ");
            
            // check if the input is a number: if so return it (exiting)
            if (!isNaN(spend)) {
                return Number(spend);
            }
            alert("Hmmm... I'm not sure I understood. Please try again.");
            console.log("Spend input is not a number.");
    
            count--;
            console.log(count);
        }
        // We get here when input is not a number and count = 0.
        alert("Oh no! We are unable to process your request, please try again later.");
        // return undefined is the default, so we can leave it out.
    }
    
    const budget = monthlyBudget();
    console.log("the user provided this input:", budget);