2

jsfiddle demo

Bear with me, total newb here.

I'm trying to make a simple multiplication calculator, as a experimentation with Javascript.

The catch is that -

  1. No libraries, just pure javascript.
  2. Javascript must be unobtrusive.

Now, the problem arises, that it doesn't give the value out.

When I do this locally, answer has a value of NaN, and if you hit Submit it stays that way, BUT, if you press the back button, you see the actual result.

In the JSFiddle, much is not shown, except for the fact that it simply doesn't work.

Please tell me, is it even possible to make an unobtrusive calculator? How?

(PS. I was taking a bit of help from sciencebuddies, just to see basic syntax and stuff, but I found it can't be done without code being obtrusive)

8
  • 1
    The xintox.js file is not included; also, all you need in the html frame is what's in the body (not the body element itself); you can add resources through the Resources menu on the left. Commented Aug 18, 2012 at 14:54
  • Also, you can't just say Xintox.blahblahblah. You need to use a method like document.getElementByName. Commented Aug 18, 2012 at 14:56
  • I must have forgot to remove the script code, the xintox.js is the JS provided in the fiddle itself. There is no more code, except in the fiddle. Commented Aug 18, 2012 at 14:56
  • Edited but you need to add the Xintox and CSS resources: jsfiddle.net/userdude/EptAN/2 @Linuxios - That may be true, but see the getE() function in my edited fiddle. Commented Aug 18, 2012 at 14:56
  • @Linuxios, I have added the getE in my own, original fiddle. Also, I saw the formname.formelementname method [sciencebuddies.org/science-fair-projects/project_ideas/…, is it deprecated or something? Commented Aug 18, 2012 at 15:01

3 Answers 3

5

I realize you're probably just getting started and don't know what to include, remove, and whatnot. But, good advice here, clearly label your elements so you can understand them, and pare it down to the smallest possible code you need for it to work (even less, so you can build it up).

Here is your code reworked:

HTML

<div>
    <input type="text" id="multiplicand" value="4">
    <input type="text" id="multiplier" value="10">
    <button type="button" id="multiply">Multiply</button>
</div>
<p id="result">
    The product is: <span id="product">&nbsp;</span>
</p>

Javascript

window.onload = function(){
    var button = el('multiply'),
        multiplicand = el('multiplicand'),
        multiplier = el('multiplier'),
        product = el('product');

    function el(id) {
        return document.getElementById(id);
    };

    function multiply() {
        var x = parseFloat(multiplicand.value) || 0,
            y = parseFloat(multiplier.value) || 0;

        product.innerHTML = x * y;
    }

    button.onclick = multiply;
};

http://jsfiddle.net/userdude/EptAN/6/

A slightly more sophisticated approach, with add/subtract/multiply/divide:

http://jsfiddle.net/userdude/EptAN/9/

Sign up to request clarification or add additional context in comments.

14 Comments

Might want to add type=button to the <button> tag because in some browsers the type defaults to "submit".
Thanks a lot! :D EDIT: Could you explain where did I go wrong?
Just in case someone wonders, the ... || 0 part means if ... was NaN or 0, use the value 0
@ajax333221 , how is it decided whether parseFloat is to be chosen, or 0? Does parseFloat give a value of False or something, in case NaN is found? AFAIK, || = or, right?
@Namanyayg - See this fiddle for a way to see if you're multiplying by 0 (which I evaluate NaN to with the || 0, as ajax333221 notes).
|
1

You have to change the submit button so that it doesn't submit the form. Right now clicking "Submit" causes the form submits to the same page which involves a page reload.

Change the <input type="submit" id="submitt"> to <button type=button> and it should work.

You can probably do without the <form> element in the first place. That'll stop clicking enter in your text input from reloading the page.

4 Comments

No, it still won't work properly, but that's definitely necessary.
I thought that the form "binds" them together, and I saw the syntax formname.formelement.value, so I thought that's the way to go. Thanks for this :D @Pointy what more is to be added?
Well Jared Famish has given a pretty thorough answer that covers things well.
@Namanyayg, the onclick handler binds them together sufficiently well without the side effect of wiping out the current page state.
1

Your example has a couple of problems:

  1. The form still submits. After the JS changes the value, the submit will cause the page to reload, and that work you've done setting the answer value is wasted.
  2. You're trying to do this stuff right away. In the header, none of the body has been parsed yet (and thus, the form elements don't even exist). You'll want to wait til the page is loaded.
  3. The script hijacks window.onload. If you don't have any other scripts on the page, that's fine...but the whole point of unobtrusive JS (IMO) is that nothing breaks whether the script is there or not.

Fixed, we have something kinda like:

// Wrap this onload in an IIFE that we pass the old onload to, so we can
// let it run too (rather than just replacing it)
(function(old_onload) {

  // attach this code to onload, so it'll run after everything exists
  window.onload = function(event) {

    // run the previous onload
    if (old_onload) old_onload.call(window, event);

    document.getElementById('Xintox').onsubmit = function() {
      var multiplier = +this.multiplier.value;
      var multiplicand = +this.multiplicand.value;
      this.answer.value = multiplier * multiplicand;
      return false;  // keep the form from submitting
    };
  };​
})(window.onload);

Note i'm attaching the meat code to the form, rather than the button, because hitting Enter in either of the factor boxes will trigger a submit as well. You could still attach to the button if you wanted, and just add a submit handler that returns false. But IMO it's better this way -- that way the form works just the same with JS as without (assuming the script on the server fills in the boxes appropriately), except it won't require a round trip to the server.

6 Comments

A few questions - What's an IIFE? How does using old_onload help? Why is there a bracket before 'function'? Explain the 'if' statement please? Shouldn't it have {} ? What does +this mean? What does this.answer.value give? Does 'this' here means 'Xintox' ? What does the (window.onload) at the end do? Thanks :)
An IIFE ("Immediately Invoked Function Expression") is a function that you execute right as you define it, often without even so much as giving it a name. (function() {})() is an IIFE. It's used to avoid globals, and/or to rename stuff within the function. (You'll often see it in jQuery plugins, in the form (function($) {...})(jQuery), because $ is convenient and stands out, but other scripts may have hijacked it). You could say var old_onload = window.onload; and forgo the IIFE, but since it's running in the global scope, old_onload is global even though you use var.
The if statement calls the old onload if there was one. We can't be sure whether it was there or not, so we can't just call it. You don't need the {} because it's a single statement; you only need {} if you have more than one statement to execute. (Some people say to use them always, but they don't really serve a purpose in this case.)
+expression is one of a few ways to cast expression to a number. Works kinda like parseInt, but uses JS's type coercion rules. See, + (as a unary operator) takes a number, and...well...doesn't do anything to it. (It's there for symmetry with -, and is equivalent to -(-expression), but without the extraneous math.) But it only works on numbers, so JS casts expression to a number for you.
Since the event handler is a property of the form, and will conceptually be called somewhat like theForm.onsubmit(event) by the browser on submit, when it runs this is set to the form element. In this case, yes, that's the form with the id of "Xintox".
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.