4.4: Input Validation

Learning Objectives

By the end of this lesson, you should:

  • Be familiar with the concept of "Data Types".

  • Understand what input validation means and why we use it.

  • Know how to use the Number() function to convert a string to a number.

  • Know what the NaN data type is.

Introduction

So far in any of our dice-guessing games, the program doesn't restrict players from entering "bananas", 38373, or any value other than 1 to 6. In the way we've written our code so far, there may not be errors for invalid input, but there will be situations in SWE Fundamentals where invalid input causes syntax or logical errors. To preempt these errors, we may wish to guide the player by providing feedback when their input is invalid.

We will use our dice game to demonstrate input validation. We'll first see how to detect if the player typed in a number, then we'll detect if the player's number is within the desired range of 1 to 6.

Input Data-Type Validation

When running the main function via clicking the submit button, the input parameter will always be a string data type. The input string may sometimes contain number characters - e.g. "5", "9383733", or a combination of letter with number characters, e.g. "abc123", but the variable will nonetheless be of type string.

How can we check if the characters in input are only numbers? If we expect only number characters, how can we convert input to be a number and not a string?

Number Function

We can try to convert a variable from string to number type with the Number function. If the string value has only number characters in it, Number will transform the string into a number.

var input = '444';
var inputNum = Number(input); // inputNum is 444

In certain projects and exercises during SWE Fundamentals, we will compare the value of input with a number as part of program logic. This can result in unexpected errors if we do not transform input from string to number first.

Whenever we expect input to represent a number, we should always cast it to a number with Number(input) before using it. This will help prevent unexpected errors where input may not equal what we expect, for example when comparing "1" with 1.

NaN

When we use the Number function to convert a value that isn't only numbers, Number may return a NaN value. NaN stands for "not a number". For example, the following code generates NaN.

var input = 'papayas';
Number(input);

NaN also occurs when we attempt a math operation that doesn't result in a valid number. The following are examples.

2 * 'chocolate';
'dogs' / 32;
0 / 0;

Note that NaN is a valid value in JavaScript, like 0 or 1. The following examples store NaN in variables.

var count = NaN;
var count = 'papayas' * 12;
var input = 'papayas';
var inputCount = Number(input);

Number Type Validation Logic

We can use NaN to write logic like the following.

If we try to convert a value to a number and we get the result NaN, then the value is not a number.

Number.isNaN

To help us implement our logic above, JavaScript provides a Number.isNaN function that returns whether a given value has value NaN. This is because a direct comparison of a value with NaN doesn't work in JavaScript. The following code would not work as we might expect.

// this will say FALSE, which is incorrect
Number('bananas') == NaN;

The following is an example of Number.isNaN, which is built-in to JavaScript. Number.isNaN returns a boolean value.

var input = 'hello';
var result = Number(input);
console.log(Number.isNaN(result));

To complete our logic, we might add a conditional such that our code looks like the following.

This is an example of an if/else conditional. The else code block will be executed only when the if code block is not fulfilled. In this case, only when Number(input) is NOT "Not a Number" (meaning it IS a number), the program will execute the else code block to run the regular game logic. Otherwise, if Number(input) is "Not a Number", only the if code block is executed and the regular game logic within the else block will not.

if (Number.isNaN(Number(input))) {
  myOutputValue = 'sorry please enter a number.';
} else {
  // regular app logic here
}

Input Range Validation

Now that we've verified that input contains only numbers, let's verify that input is between 1 and 6. We could write a long conditional like the following...

if (
  input == 1 ||
  input == 2 ||
  // ... etc
) {
  // ...
}

...or we could express this range with comparison operators less than or equal to (<=) and greater than or equal to (>=). The if conditional in both examples evaluates to true when input is between 1 and 6.

// if number is greater than or equal to 1 AND less than or equal to 6
if (input >= 1 && input <= 6) {
  // number is between 1 and 6
}

Note the functionality of the 2nd example is the same as the 1st, easier to understand, and easier to write, especially when we have a wider range, for example with a 20-sided dice. There are other ways to validate a number range, for example with less than (<) and greater than (>) operators like we do below.

Dice Game Code With Input Validation

Our dice game code looks like the following with input validation.

var rollDice = function () {
  // produce a decimal between 0 and 6
  var randomDecimal = Math.random() * 6;
  // remove the decimal
  var randomInteger = Math.floor(randomDecimal);
  // add 1 to get a number between 1 and 6 inclusive
  var diceNumber = randomInteger + 1;
  return diceNumber;
};

var main = function (input) {
  var myOutputValue = '';

  // first check if input is a number
  if (Number.isNaN(Number(input)) == true) {
    myOutputValue = 'sorry please enter a number.';
  } else {
    // then check if input is between 1 and 6
    if (input < 1 || input > 6) {
      myOutputValue = 'sorry please enter a number from 1 - 6';
    } else {
      // the input is 1-6, go ahead with the dice game
      var randomDiceNumber = rollDice();
      if (randomDiceNumber == input) {
        myOutputValue = 'you win';
      } else {
        myOutputValue = 'you lose';
      }
    }
  }

  return myOutputValue;
};

Simplify Logic with Multiple return Statements in Single Function

You may notice that the above example has several levels of nested if and else statements. If we have more types of input validation, this can make our code unnecessarily complex. Luckily, there is a simple way to reduce complexity by using multiple return statements in our functions.

Notice the multiple return statements in the main function below. This simplifies our logic by reducing nesting of if and else blocks. Functions exit after return statements, i.e. nothing in the function is executed after return, making return statements convenient ways to exit our logic if input is invalid.

var rollDice = function () {
  // produce a decimal between 0 and 6
  var randomDecimal = Math.random() * 6;
  // remove the decimal
  var randomInteger = Math.floor(randomDecimal);
  // add 1 to get a number between 1 and 6 inclusive
  var diceNumber = randomInteger + 1;
  return diceNumber;
};

var main = function (input) {
  var myOutputValue = '';

  // first check if input is a number
  if (Number.isNaN(Number(input)) == true) {
    myOutputValue = 'sorry please enter a number.';
    return myOutputValue;
  }

  // then check if input is between 1 and 6
  if (input < 1 || input > 6) {
    myOutputValue = 'sorry please enter a number from 1 - 6';
    return myOutputValue;
  }

  // the input is 1-6, go ahead with the dice game
  var randomDiceNumber = rollDice();

  if (randomDiceNumber == input) {
    myOutputValue = 'you win';
    return myOutputValue;
  }

  myOutputValue = 'you lose';
  return myOutputValue;
};

Exercises

Add Validation to Past Game

Choose one of your previous dice game implementations and add validation logic from this module.

Last updated