1

I'm currently working my way through a beginner's JavaScript course on Treehouse and keep getting stuck on functions. In effort to understand better, I tried creating a calculator which converts human years to dog years. Here is my code so far:

HTML:

<div id="calculator">
  <form>
    <label>What is your current age in human years? <br>
    <input type="text" id="humanYears"></label> <br>
    <button type="text" id="calculate">Calculate</button>
  </form>
</div>

JS:

function calculate() {
 var humanYears = document.getElementById("humanYears").value;
 var dogYears = (humanYears * 7);
 document.write(dogYears);
}

document.getElementById("calculate").onclick = function(){calculate(); };

The page flickers and I keep seeing the form, no result.

I know this code is incorrect but I don't understand why. I also know I can just copy other people's code from Github and have a functioning calculator but that kind of defeats the purpose of learning. I would rather know why my code doesn't work and what I can do to fix it. (I double, triple checked that the HTML and JS files were properly linked, which they are.)

Any JS wizards out there care to chime in?

Edit: When I enter an age into the form, it merely reloads, rather than displaying the age in dog years (which is the desired outcome).

JSJunkie
  • 39
  • 5
  • 2
    Misuse of [`document.write`](https://developer.mozilla.org/en-US/docs/Web/API/document.write). "... calling document.write on a closed (loaded) document automatically calls document.open, which will clear the document." – Teemu Apr 19 '16 at 18:26
  • There are a few issues. `document.write` is one, another is that you're closing your `input` tag with a `label` tag, so I don't think it actually pulls any value from it. – sg.cc Apr 19 '16 at 18:28
  • 2
    @sg.cc the input element does not have an end tag – PDN Apr 19 '16 at 18:29
  • 1
    @sg.cc: ``s are not closed, it's just closing the ` – Bergi Apr 19 '16 at 18:29
  • @Teemu should submit as an answer – PDN Apr 19 '16 at 18:30
  • see [Why is document.write considered a “bad practice”?](http://stackoverflow.com/q/802854/1048572) and maybe [Why does jQuery or a DOM method such as getElementById not find the element?](http://stackoverflow.com/q/14028959/1048572) – Bergi Apr 19 '16 at 18:31
  • 2
    How is the code incorrect? What happens when you click the button? Are you getting any error messages in your devtools console? Without knowing what does not work, we can't help you fix it. – Bergi Apr 19 '16 at 18:32
  • Thanks so much everyone! @Bergi The form and calculate button load, but then when I enter an age and click "calculate", the form just refreshes without displaying the number of dog years. – JSJunkie Apr 19 '16 at 18:35
  • @JSJunkie: Sounds like you need to put a `preventDefault` in there to keep the form from submitting – Bergi Apr 19 '16 at 18:38
  • @JSJunkie You should update your question with that critical information. – George Stocker Apr 19 '16 at 18:43
  • Hi @GeorgeStocker, I updated the question. Someone else also added an edit to my post ("The page flickers and I keep seeing the form, no result.") Please let me know if there are any other changes that need to be made. Thanks. – JSJunkie Apr 19 '16 at 19:50

3 Answers3

1

Your code works, although as you've indicated it's not great.

function calculate() {
 var humanYears = document.getElementById("humanYears").value;
 var dogYears = (humanYears * 7);
 document.write(dogYears);
}

document.getElementById("calculate").onclick = function(){calculate(); };
<div id="calculator">
  <form>
    <label>What is your current age in human years? <br>
    <input type="text" id="humanYears"></label> <br>
    <button type="text" id="calculate">Calculate</button>
  </form>
</div>

Some notes for improvement:

  • Avoid document.write
  • Forms should have submit buttons (either <input type="submit" value="Calculate"> or <button type="submit">Calculate</button>
  • The parentheses around your arithmetic are superfluous: var dogYear = humanYears * 7; is sufficient
  • Not everything needs an id attribute, although that makes DOM queries easy and quick
  • You should handle the form's submit event as opposed to the button's click event as you'll want to handle if, say, I submit the form by pressing Enter on my keyboard
  • You don't need the extra function around calculate, document.getElementById('calculate').onclick = calculate; would suffice

With those notes in mind, here's how I'd improve your calculator:

var form = document.getElementById('calculator');

function calculate() {
  var years = form['humanYears'].value,
      dogYears = years * 7;

  document.getElementById('answer').innerText = dogYears;  
}

form.addEventListener('submit', calculate, false);
<form id="calculator">
  <p>
    <label>
      What is your current age in human years?<br>
      <input type="text" name="humanYears">
    </label>
  </p>
  <p>
    <button type="submit">Calculate</button>
  </p>
  <p>
    Answer: <span id="answer"></span>
  </p>
</form>

Things I've changed:

  • I'm using <p> tags to control whitespace instead of <br> which will further let me customize presentation with CSS if I choose to. You cannot style <br> elements.
  • I'm modifying a portion of the DOM, not the entire DOM
  • I've bound my event handler with addEventListener which is way less obtrusive
  • I'm accessing form elements through the natural structure the DOM provides instead of running a full DOM query for each element
  • I've reduced some code
André Dion
  • 19,231
  • 7
  • 52
  • 59
0

The main problem is that document.write doesn't do what you imagine it does:

Note: as document.write writes to the document stream, calling document.write on a closed (loaded) document automatically calls document.open, which will clear the document.

See the documentation for document.write: https://developer.mozilla.org/en-US/docs/Web/API/Document/write

A better way to this is to have an empty element on the page, which you then change the contents of:

function calculate() {
    var humanYears = document.getElementById("humanYears").value;
    var dogYears = humanYears * 7;
    document.getElementById('output').innerText = dogYears;
}

document.getElementById("calculate").onclick = calculate;
<div id="calculator">
  <form>
      <label>What is your current age in human years? <br>
          <input type="text" id="humanYears">
      </label>
      <br>
      <button type="button" id="calculate">Calculate</button>
      <div id="output"></div>
  </form>
</div>

I've also made some small improvements to your script:

  • Changed the indentation of your HTML to be more readable
  • Changed your button to have type="button" - otherwise your form will submit and the page will reload when you click the button. In this case, you actually don't even need a form element, but it's not hurting anything. Alternatively, you could add return false to your calculate function - this would tell the browser not to submit the form and thus not reload the page
  • Changed how you're adding the onclick handler - there's no need to wrap the calculate function in another function. In javascript, functions can actually be passed around like a variable. This is why I set the value of onclick to just be calculate - notice however that I left out the (). You want the onclick to be a reference to the function, otherwise the calculate function would be executed immediately, and the onclick would be set to the return value of the function - in this case, that would be undefined.
corinnaerin
  • 349
  • 5
  • 12
0

Here your working code with as little changes as possible:

<div id="calculator">
  <form>
    <label>What is your current age in human years? <br>
    <input type="text" id="humanYears"></label> <br>
    <button type="text" id="calculate">Calculate</button>
  </form>
</div>

<script>
  function calculate() {
    var humanYears = document.getElementById("humanYears").value;
    var dogYears = (humanYears * 7);
    document.write(dogYears);
  }

  document.getElementById("calculate").onclick = function(){calculate(); return false; };
</script>
  • Assuming you put everything in one file the script tags are missing. If not then you still need a script tag to load the JS file.
  • Your function needed a "return false;". If you omit that, the page will reload after writing your output and won't see the output. That happens because the default behaviour of a button in a form is to reload the page. By returning "false" you suppress that.
TehSphinX
  • 5,497
  • 1
  • 16
  • 30