# 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.

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

{% hint style="warning" %}
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.
{% endhint %}

### NaN

{% embed url="<https://youtu.be/P24Rp6HmMkM>" %}

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`.

```javascript
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.

```javascript
2 * 'chocolate';
```

```javascript
'dogs' / 32;
```

```javascript
0 / 0;
```

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

```javascript
var count = NaN;
```

```javascript
var count = 'papayas' * 12;
```

```javascript
var input = 'papayas';
var inputCount = Number(input);
```

#### Number Type Validation Logic

{% embed url="<https://youtu.be/6RMjO0FbyQc>" %}

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.

```javascript
// 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.

```javascript
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.

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

### Input Range Validation

{% embed url="<https://youtu.be/mjkj-OfCLKc>" %}

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...

```javascript
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.

```javascript
// 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.

```javascript
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.

```javascript
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.
