0

I want to know why my console won't log the appropriate logs. The error is saying that my .addEventListener() is null but how so?

I tried:

Removing return false but that didn't help.

Here's gameTime.html

<!DOCTYPE html>
<html lang="en">
<head>
    <script type="text/javascript" src="gameTime.js"></script>
    <meta charset="utf-8">
    <title>WOMP</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <link rel="stylesheet" href="gameTime.css">
</head>     
<body>
    <form class="col-md-4 col-md-offset-4" name="formHandler" id="handle">
  <div id="allFields">
    <div class="moveUsername">
      <h1>(All numbers inputted will be assumed that it's in dollars)</h1>
      <label for="usr">What's your annual salary?</label>
   <input type="field" class="form-control" id="salary" placeholder="What's your annual salary?" required="required">
    </div>

    <div class="ageMovement">
      <label for="usr">How much do you spend every month on bills?</label>
      <input type="field" class="form-control" id="monthlyBills" name="ageChecker" placeholder="How much do you spend every month on bills?" required="required">
    </div>

    <div class="emailMovement">
      <label for="usr">How much do you spend when going out?</label>
      <input type="field" class="form-control" id="goingOut" name="emailChecker" placeholder="How much do you spend when going out?" required="required">
    </div>
        <button type="submit" id="btnSubmit" class="btn btn-default">Submit</button>
    </form>
</body>
</html>

Here's gameTime.js

(function() {
  function Finance(salary, fixedExpense, variableExpense) {
    this.salary = salary;
    this.fixedExpense = fixedExpense;
    this.variableExpense = variableExpense;
    this.isSalaryZeroOrLess = function() {
      var s = parseInt(document.getElementById("salary").value);
      console.log(this); 
      if (s <= 0) {
        console.log("No money");
      } else if (this.greaterThan()) {
        console.log("Testing");
      } else {
        console.log("Money: ", s);
      }
    }
  }

  Finance.prototype.greaterThan = function() {
    var s = parseInt(document.getElementById("salary").value);
    var userSalary = s / 12;
    console.log(userSalary);
    if (userSalary < 30000) {
      console.log("works!");
    }
  }

  var fin = new Finance(1000, 1000, 1000);

  document.querySelector("#btnSubmit").addEventListener("click", fin.isSalaryZeroOrLess);
  return false;
})()

Here are the errors:

Uncaught TypeError: Cannot read property 'addEventListener' of null
at gameTime.js:30
at gameTime.js:32
Scott Marcus
  • 57,085
  • 6
  • 34
  • 54
chompy
  • 145
  • 7
  • Try using `document.getElementById("#btnSubmit").addEventListener(...` – NewToJS Dec 26 '16 at 19:42
  • Try `document.getElementById("btnSubmit").addEventListener("click", fin.isSalaryZeroOrLess);` – Hicaro Dec 26 '16 at 19:43
  • 1
    "The error is saying that my .addEventListener() is null" — No, it doesn't. It says it isn't a property **of** null. – Quentin Dec 26 '16 at 19:48
  • 1
    It's `document.querySelector("#btnSubmit")` that is `null`, not `.addEventListener()`. – Bergi Dec 26 '16 at 19:49
  • **Do not** repost [the same question](http://stackoverflow.com/q/41334668/157247) (10k+ only, it's deleted) when the community has already dealt with it once. – T.J. Crowder Dec 27 '16 at 08:33

1 Answers1

2

You are running the JavaScript before the HTML has been fully parsed. So when your addEventListener() line is executed, the #btnSubmit element hasn't even been reached yet.

Move this:

<script type="text/javascript" src="gameTime.js"></script>

out of the head section so that it is just before the </body> tag:

    <script type="text/javascript" src="gameTime.js"></script>
</body>
</html>

That way, all of the HTML that makes up the body of your page will have already been loaded and in memory when the script is executed. Additionally, by loading scripts at the end of the HTML, the page will render to the user a little quicker than if the script is at the top of the page because while a script is loading and executing the browser is blocked from doing anything else.

FYI: the return false; at the end of your function is doing nothing for you since:

  1. It's the last line of the function so, the function was going to return anyway.
  2. It's a self-invoking function that is not being assigned to another identifier, so the return value is never captured.

Also, your Finance function is not being exposed outside of your IIFE, so you will never be able to use it outside of it.

Scott Marcus
  • 57,085
  • 6
  • 34
  • 54
  • 1
    So basically apply event handlers when the dom is ready. `window.onload=function(){//Add event listeners here};` could be used for those who like to keep their `script` tags within the `head` tag. – NewToJS Dec 26 '16 at 19:44
  • 3
    That is one way to do it, but by moving the script, there is less code to type and the page is not blocked from rendering while the script loads. – Scott Marcus Dec 26 '16 at 19:45
  • The page isn't blocked. That will only run once the page has loaded hence using it. Some people like keeping scripts in the head of the page rather then at the bottom. This why why I'm commenting/contributing to this post. – NewToJS Dec 26 '16 at 19:47
  • 2
    You are incorrect about the page being blocked. That's why the prevailing wisdom is to load scripts at the bottom of the page. See: https://developer.yahoo.com/performance/rules.html – Scott Marcus Dec 26 '16 at 19:50
  • @NewToJS — Yes, it is. Script elements (which are not async) block parsing of HTML in case they include document.write statements. – Quentin Dec 26 '16 at 19:50
  • OMG, THIS IS WHAT THE PROBLEM WAS? I was pulling my hair out for 4 hours... Thank you so much :D. *gives hug*. – chompy Dec 26 '16 at 20:02
  • No problem! Good luck! – Scott Marcus Dec 26 '16 at 20:03
  • @chompy: Yes, this was the problem, as [the answer](http://stackoverflow.com/a/8716680/157247) to the question [your original version of this](http://stackoverflow.com/q/41334668/157247) was closed as a duplicate of quite clearly said. Here's the opening sentence of that answer: *"The element you were trying to find wasn’t in the DOM when your script ran."* Next time, when the community points you at something, read it thoroughly and think about it carefully, rather than deleting your closed question and reposting the exact same thing again. – T.J. Crowder Dec 27 '16 at 08:35