Bummer! You must be logged in to access this page.

Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

JavaScript MASH Game Will Not Work

Clicking the Tell My Fortune button just takes you back to the top of the page. I have linked the html, css, and js so I'm wondering what is wrong/missing. Thanks!

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">

  <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=0.5, maximum-scale=0.5, minimal-ui">

  <title>Futuristic MASH</title>
  <link href="normalize.css" rel="stylesheet">
  <link href="style.css" rel="stylesheet">
</head>
<body>

  <h1 class="logo"><img src="img/ddlogo.png" /></h1>
  <p class="description">Enter your choices and your character will be revealed!</p>

<form action="" method="post" id="mash">

  <div id="answers" class="hide">
      <p>Your race is <span id="race"></span> with a class of <span id="background"></span> and a background of <span id="class"></span> who owns a <span id="weapon"></span>.
  </div>

  <div class="bucket">

    <div class="choice-bucket">
      <h4 class="highlight">What is your chosen race?</h4>
        <input name="race[]" type="text">
        <input name="race[]" type="text">
        <input name="race[]">
        <input name="race[]">
      </div>

      <div class="choice-bucket">
        <h4 class="highlight">What is your class?</h4>
          <input name="class[]">
          <input name="class[]">
          <input name="class[]">
          <input name="class[]">
      </div>

     <div class="choice-bucket">
        <h4 class="highlight">What is your background?</h4>
          <input name="background[]">
          <input name="background[]">
          <input name="background[]">
          <input name="background[]">
      </div>

  </div>

  <input type="submit" value="Tell my fortune">
</form>
<script src=""></script>
</body>
</html>

and

function random_number(num) {  // New function called random_choice that takes one parameter, num (or a number)
    // Get a random number between 0 and a passed-in number
    var num = num || 4  // If no number passed in, default to 4
    return Math.floor(Math.random() * num); // Round the answer down (floor) of a random number between 0 and 1 and multiply it by a number. Then return a value and exit the function.
}

function mash_choice() {  // New function called mash_choice that doesn't take any parameters 
    // Since MASH is a special case, give it its own list
    var mash = ['sword', 'mace', 'axe', 'staff'];  // The array of choices to pick from 
    var randomNum = random_number(4);  // Use the above function to get a number between 0 and 4
    return mash[randomNum];  // Return the list item the random number function just picked and exit the function 
}

function get_answer(category) { 
    // Get a random answer from the available answers in a given category
    var choices = [];  // A blank array to hold the user provided answer  
    var selector = 'input[name="' + category + '[]"]';  // Build a CSS selector for the blanks in our passed in category 
    var inputs = document.querySelectorAll(selector);  // Get all of the inputs that match our selector 
    var answer;  

    for (var i = 0; i < inputs.length; i++) {  // Begin a for loop that will run through the code. i++ = add one to the counter which is "i"
        answer = inputs[i].value;  // Get the input with the index value of the counter and get the value ie. if they typed in dog, you get back "dog" 
        if (answer !== '') {  // If answer doesn't equal a blank... !== means doesn't equal 
            choices.push(answer); //...add it to the end of the list 
        }
    }
    return choices[random_number(choices.length)];   // Pick and return a random choice choice.length = number of answers the user provided in that category 
}

function fill_in_answers(answers) {
    // Find the spans that need filled
    var weapon = document.querySelector('#weapon');  // This says make a new variable and find the HTML tag that has the ID of "weapon" 
    var race = document.querySelector('#race');
    var class = document.querySelector('#class');
    var bg = document.querySelector('#bg');

    // Fill them with the provided answers
    weapon.innerText = answers['mash'];
    race.innerText = answers['race'];
    class.innerText = answers['class'];
    bg.innerText = answers['bg'];
    weapon.innerHTML = answers.mash;  // Change the content of the element in the HTML doc with the id "weapon" to the "mash" value in answers 
    race.innerHTML = answers.race;  // Change the content of the element in the HTML doc with the id "career" to the "career" value in answers 
    class.innerHTML = answers.class;
    bg.innerHTML = answers.bg;
}

function handle_submission(evt) {
    evt.preventDefault();  // Stop the form from reloading the page 
    evt.stopPropagation();  // Stop the form from reloading the page

    // Build up our answers object
    var answers_object = {
        'mash': mash_choice(),
        'race': get_answer('race'),
        'class': get_answer('class'),
        'bg': get_answer('bg')
    }
    // Fill in the answers
    fill_in_answers(answers_object);

    var answer_div = document.querySelector('#answers');
    answer_div.classList.add('show');
}

// Find the form on the page and attach a handler for when it's submitted
var form = document.querySelector('#mash');  
form.addEventListener('submit', handle_submission);  // Anytime the form is submitted, we want to call the function handle_submission 

2 Answers

I really like what you're doing here to mash it up. :-D

There are 2 problems that are causing this app to not run properly. One issue is that there is a variable's name which is a word that JavaScript claims as it's own which prevent anyone from using that word as a variable name. The other issue is what can by reduced to being a typo.


Inside the fill_in_answers() function there is a variable name called, class. The word, "class" is one of several reserved keywords in Javascript.

We could simply change var class to anything else, such as, var cls. I felt, however, that "class" is really what is most descriptive since the subject of the app is, at least in part, inspired by Dungeons and Dragons. In JavaScript we are able to begin variable names with the characters: $,_, or any symbol with the Unicode derived core property ID_Start. You may already be familiar with the dollar sign ($) at the beginning of variable names, as that is what jQuery has chosen to use.

I chose to use the dollar sign ($) as well, since we will only be impacting the local variables within a single function -- fill_in_answers(). To be consistent with this naming pattern, all the variable names have the dollar sign ($) added to the beginning of them. The updated function will be shown later in this post.


The next issue we have to fix has to do with the "Background" portion of the app. More specifically the consistency of using "background" versus "bg". In some lines of code the letters, "bg", were introduced where the word, "background" was expected. This was resulting in a Null value being set for one of the variables.

We need to make some edits in each file.

Within the HTML file, inside the #answers div, replace:

<!-- NOTE: The id's for the spans, #background and #class, are switched -->
<p>Your race is <span id="race"></span> with a class of <span id="background"></span> and a background of <span id="class"></span> who owns a <span id="weapon"></span>.

with:

p>Your race is <span id="race"></span> with a class of <span id="class"></span> and a background of <span id="background"></span> who owns a <span id="weapon"></span>.

Within the JavaScript file we will replace any instance of "bg" with "background":

// Inside function handle_submission
    // Change the last property/value in the answers_object
    var answers_object = {
        'mash': mash_choice(),
        'race': get_answer('race'),
        'class': get_answer('class'),
        //'bg': get_answer('bg')
        'background': get_answer('background')
    }

// Inside function fill_in_answers
    /** Rewrite the contents of the function
     *      - by adding a dollar sign ($) to each of the variables
     *      - replace all instances where "bg" is used with "background"
     **/

     // Find the spans that need filled
    var $weapon = document.querySelector('#weapon');  // This says make a new variable and find the HTML tag that has the ID of "weapon"
    var $race = document.querySelector('#race');
    var $class = document.querySelector('#class');
    var $background = document.querySelector('#background');

    // Fill them with the provided answers
    $weapon.innerText = answers['mash'];
    $race.innerText = answers['race'];
    $class.innerText = answers['class'];
    $background.innerText = answers['background'];
    $weapon.innerHTML = answers.mash;  // Change the content of the element in the HTML doc with the id "weapon" to the "mash" value in answers
    $race.innerHTML = answers.race;  // Change the content of the element in the HTML doc with the id "career" to the "career" value in answers
    $class.innerHTML = answers.class;
    $background.innerHTML = answers.background;

The app now functions correctly because of the edits we made. :-D

I'll make the changes and run this when I get home but THANK YOU for your detailed answer and explanation. I can't even begin to tell you how helpful that was.

I've correctly linked the JS now:

<script src="script.js"></script>

But the button now does nothing.