BACK 
Part 2a  A calculator (Simply done!)


Planning
Okay, so we want to write a JavaScript calculator. Let's not (initially)
be too ambitious. All our calculator will do is basic arithmetic: add,
subtract, multiply and divide. Hmm, what about negative numbers  so
we also need to be able to change the sign of a number. What else?
Well, we're going to allow rather big numbers, so it's a good idea to
have a button that easily allows us to enter an exponent (the number
times 10^{something}). We need a decimal point. And we need to
be able to clear the display (a CLEAR button), and to clear everything
(ALL CLEAR). Let's list out requirements up to now:
 A display area for numbers
 Buttons for 0,1,2, up to 9
 A decimal point button
 A button to change the sign (+/)
 Clear and all clear (C, AC buttons)
 Function buttons (* / + )
 An exponent button (EXP)
 A 'calculate' button (The = button)
Let's group our different buttons and boxes into three classes:
 The display area
 The numeric buttons (0 to 9, +/, .)
 Function buttons together with AC, C, = and EXP
Why not position these in a table, thus:
Display Area 
Numeric Buttons 
Function Buttons 
Even at this early stage, we also need to think about what can
go wrong. Hmm. Here are a few possibilities:
 Too many digits are entered
 The result of a calculation is too 'big' to show (too large and positive,
or too large and negative)
 The result of a calculation is too small to show (for example, 1*10^{1000})
 We divide something by zero
 JavaScript bombs out because of internal calculation problems,
for example if we divide 10^{1000} by 10^{1000} 
we know that the answer is 1, but does JavaScript?
We therefore must trap numbers that appear too long (although this is
to a certain extent a matter of taste); we must show appropriate error
messages with divide by zero and numbers that are out of range (most
JavaScript implementations seem happy up to about 10^{±320});
tiny tiny tiny numbers can be represented as zero; and we also need
a way to alert the user to JavaScript's occasional troubles with large
numbers.
Writing the HTML
As our basic calculator, we'll use the following table:
HTML code for our basic calculator

<div align="center">
<table width="30%" border="4">
<tr><td colspan="2" align="center">Display Area</td></tr>
<tr><td>Numeric Buttons</td>
<td>Function Buttons</td>
</tr></table></div>

Which implements the layout we discussed in "Planning"
above. We need to put all of the above inside
a <FORM> .. </FORM> pair of tags, and then we need to
create buttons for each of the numbers and functions we talked about
when we planned things.
How do we create buttons? Well, we could do what we did on the
first page of our JavaScript tutorial, and hijack a <input type="reset">
button, but there is a better way. All recent and respectable variants of
JavaScript (but not, for example, some earlier releases of IE 3) have
the following type of input:
<input type="button">
Which gives us a generalpurpose button. To each of these buttons we'll
attach a:
OnClick="DoSomething()"
'event handler', so that when we click on the button, we can expect
a response. We'll discuss each of these responses in the
Calculator Functions section below. For now, let's
draw our calculator:
More detailed HTML for basic calculator

<FORM name="Calculator">
<table border="4"> <!OUTER BORDER OF CALCULATOR, PANELS>
<tr> <!TOP PANEL>
<td colspan="2">A Simple JavaScript Calculator<br>
<input type="text" maxlength="40" size="30" name="Display">
</td>
</tr> <!END TOP PANEL>
<tr>
<td> <!LEFT PANEL>
<table>
<tr>
<td><input type="button" value="7"></td>
<td><input type="button" value="8"></td>
<td><input type="button" value="9"></td>
</tr>
<tr>
{all other rows of digits are similar..}
</tr>
</table>
</td><!END LEFT PANEL>
<td> <!RIGHT PANEL>
<table>
{right panel is similar in overall structure to left}
</table>
</td><!END RIGHT PANEL>
</tr></table>
</FORM>

We've colourcoded things to make them a bit easier. FORM
elements are in red, the outer table is bold, and
tables inside tables are in blue. You can see
that we've preserved our basic structure that we talked about previously 
the top panel takes up two columns and contains a text input that we'll
use for displaying results; the bottom left panel will contain the numbers
(three examples are given), and the bottom right will contain function
buttons. Note several other things:
 The form has a name. We've called it Calculator.
 Each input button has a value  this is what will be displayed
on the button, for example "7" will be displayed on the button that
you push to generate a "7" on the display.
 The display area is unsurprisingly named Display (with a capital D),
and we've defined a width (size="30") and a maximum length of the
input string (maxlength="40").
 Each of the buttons has its own <td> .. </td>  this
keeps them nicely spaced out and regular.
Now if you take the above code and simply paste it into your webpage,
(adding in a few <td>'s and stuff),
you'll get something like the following:
.. So clearly we need to do a bit of work. We need to:
 Pretty up fonts and alignment
 Widen the buttons a lot
 Perhaps give the calculator a background colour
If you're adequate at HTML, all of this should be reasonably straightforward.
Perhaps widening the buttons needs a bit of explanation. We've given our
buttons values of "7", "8" and so on. What happens if we say:
<input type="button" value=" 7 " >
This is a good way of widening our buttons. Note that even when we
do this, all of the buttons are not quite the same width (at least, on
most browsers)! This is because the chances are your browser is using
a proportional font to write the "value" on the button. Now in Netscape,
the font can be changed for each button to a fixedwidth font (although the resulting code
looks like hell)  in IE, you don't seem to have that option (I wonder,
can you do this using style sheets?). Oh well.
Hmm, just for clarity, why don't we also name our buttons. For
example:
<input type="button" value=" 7 " name="seven" >
Play around a bit. Try the 'finished' calculator using both Netscape
and IE  you'll find that despite your finetuning, the darn thing looks
quite different. When you're happy, we're ready to move on to actually
making the thing work!
We know how to attach event handlers to each button. We simply
put:
OnClick="DoEvent()"
where DoEvent is the event handler for the relevant button.
For example, for button number seven, we might say:
<input type="button" name="seven" value=" 7 " OnClick="AddDigit('7')">
where AddDigit is the event handler. Let's now decide what
events we need. Here they are:
 Add a digit to the display
 Put a decimal point on the display (if not there already)
 Put an exponent ('e') on the display
 Change the sign to + if  and minus if plus
 Clear and All Clear (C and AC)
 Perform operations * / + and 
 Calculate (on pressing the = button)
 Hmm, what if a user types something into the tempting display
box. It seems cruel to simply discard this, so we have to enter this
(unless it's rubbish)!
Well. Let's think up names for each of these "event handlers" and
then implement each of them in turn. While we're about it, how are we
going to react when a user types something in the display box? Fortunately,
there's an event handler tailored to this need. It's called OnChange.
Here are our names for the event handlers:
Name 
Event 
What it does 
AddDigit  OnClick  Add a digit to the display 
Dot  OnClick  Put a decimal point on the display (if not there already) 
DoExponent  OnClick  Put an exponent ('e') on the display 
PlusMinus  OnClick  Change the sign to + if  and minus if plus 
Clear, AllClear  OnClick  Clear and All Clear (C and AC) 
Operate  OnClick  Perform operations * / + and  
Calculate  OnClick  Calculate (on pressing the = button) 
FixCurrent  OnChange  Process user input 
But before we implement these event handlers, we need to sort out a
few more things. First we must define the variables we will use in doing our
calculations. Here they are:
Variable 
What it stores 
Memory  The previous number you entered 
Current  The number currently being entered 
Operation  The function button you pushed, for example,

Finally, we need to define our constants. There is only one:
Constant 
What it means 
MAXLENGTH  The maximum number of digits we'll allow
a user to input. Let's make it (say) 30.

Let's get cracking:
1. First, define our constant and global variables
Variables and constant used in our JavaScript

Memory = "0"; // initialise memory variable
Current = "0"; // and value of Display ("current" value)
Operation = 0; // Records code for eg * / etc.
MAXLENGTH = 30; // maximum number of digits before decimal!

The only thing that needs explanation in the above is that we
used a numeric code for the Operation. Hmm, perhaps this is
a bit over the top. We could just keep the "*" or whatever here as
a string. But let's stick with this for the time being!
2. Define individual event handlers
2.1 AddDigit  Adding a digit to the display
JavaScript for AddDigit

function AddDigit(dig) //ADD A DIGIT TO DISPLAY (kept as 'Current')
{if (Current.length > MAXLENGTH)
{ Current = "Aargh! Too long"; //limit length
} else
{ if ( (eval(Current) == 0)
&& (Current.indexOf(".") == 1)
)
{ Current = dig;
} else
{ Current = Current + dig;
};
}; };
document.Calculator.Display.value = Current;
}

Here we see how we use the variable Current. If Current has
exceeded the allowable length, then we replace it with an error message.
Otherwise, we append the digit.
See how we use eval to check to see if Current is
zero  if it is, then we replace the zero value with the new
digit. This is to prevent a leading zero in numbers  pretty
important, as in JavaScript, a leading zero is rather peculiarly used
to indicate that we're using OCTAL, that is, base eight.
But wait a bit! What if we are busy entering 0.000 and we press say "7".
Unless we check for a decimal, this will replace the 0.000 with 7, which
is not what we intended. So we check, using the above code! If
Current.indexOf is minus one, this means that there is no decimal
point, so we can go on and replace the zero with dig. Otherwise,
we simply append the digit to the string in Current.
Then, when everything is over, we store the value in Current
into our display area. Note how we do this. We say
document.Calculator.Display.value = Current
(In fact, under Internet Explorer, it's quite okay to leave out the
document. portion, as IE works things out for itself. But Netscape will
crash and burn if you try this trick). Remember that we called our
FORM Calculator, so that's where we got this from, and that
we called the <input type="text" > box Display.
The above code can be criticised for several reasons:
 Perhaps we should first do all the processing, and then
check the string length;
 What if Current is occupied by an error message  should
we not test for this? Hmm;
 We need to handle the case where we are entering the digits
for an exponent.
Still, it gives us the flavour of what we should do, doesn't it?
JavaScript for Dot

function Dot() //PUT IN "." if appropriate.
{
if ( Current.length == 0) //no leading ".", use "0."
{ Current = "0.";
} else
{ if ( Current.indexOf(".") == 1)
{ Current = Current + ".";
}; };
document.Calculator.Display.value = Current;
}

This apparently simple function has a touch of redundancy. If the
length of Current is zero, ie Current has no contents, then
it puts in "0." rather than just the point. In addition, if there
is already a "." within Current, it does nothing. Can you
see the one remaining problem, not addressed by the above code?
Yep. Once an exponent has been entered, we probably don't want
a ".". We should check for this as well, and disable "." if an
exponent has been entered!
JavaScript for DoExponent

function DoExponent()
{
if ( Current.indexOf("e") == 1 )
{ Current = Current + "e0";
document.Calculator.Display.value = Current;
};
}

A simple function. All it does is check if an "e" is already
present within Current, and if not, insert the "e" together
with a zero exponent (for the time being) just to make things
syntactically correct.
JavaScript for PlusMinus

function PlusMinus()
{
if (Current.indexOf("e") != 1) //if there is an exponent:
{ var epos = Current.indexOf("e");
if (epos != 1)
{ Current = Current.substring(0,1+epos) + Current.substring(2+epos); //clip ve exp
} else
{ epos = Current.indexOf("e");
Current = Current.substring(0,1+epos) + "" + Current.substring(1+epos); //insert
};
} else //there is NO exponent:
{ if ( Current.indexOf("") == 0 )
{ Current = Current.substring(1);
} else
{ Current = "" + Current;
};
};
document.Calculator.Display.value = Current;
}

What does this do? If you use an ordinary calculator and press +/,
see how the sign of the number changes, but (on most machines) if
you have entered an exponent, then +/ changes the sign of the exponent!
We'll try and duplicate this. There are two main sections, represented by the
bold if .. else. If there is already an exponent, then "e" is
changed to "e", and vice versa.
On the other hand, if there is no exponent, then we check for a
leading minus, and clip it out if it is there, or insert it if it isn't.
Can you see the remaining problem? (If there is a zero on the display
and you press +/ with the above code, then you'll get "0", which is
a little clumsy). How can you fix this?
JavaScript for the Clear Buttons

function Clear() //CLEAR ENTRY
{ Current = "0";
document.Calculator.Display.value = Current;
}
function AllClear() //Clear ALL entries!
{ Current = "0";
Operation = 0; //clear operation
Memory = "0"; //clear memory
document.Calculator.Display.value = Current;
}

No surprises here. See how Clear simply clears the current number
being entered, and AllClear clears everything. We'll explore how Operation
works in the following code.
JavaScript to respond to press of arithmetic function

function Operate(op) //STORE OPERATION e.g. + * / etc.
{
if (op.indexOf("*") > 1) { Operation = 1; }; //codes for *
if (op.indexOf("/") > 1) { Operation = 2; }; // slash (divide)
if (op.indexOf("+") > 1) { Operation = 3; }; // sum
if (op.indexOf("") > 1) { Operation = 4; }; // difference
Memory = Current; //store value
Current = ""; //or we could use "0"
document.Calculator.Display.value = Current;
}

What do we want to happen when we press say "*" to say "multiply the
current number by the number I'm about to enter"? We've chosen to
 store the current number in the variable called Memory;
 Remember the multiply function in something called Operation; and
 clear the display (and Current).
There are lots of other ways we could have done things. See how we've
been a bit wicked, in that rather than storing the "*" or "/" or whatever,
we've allocated each a numeric code, and we've kept Operation as
a number.
(
Hmm. Many would frown on this practice as 'not mnemonic' 
we've chosen it because we are not entirely happy with JavaScript
comparisons in conditional statements, which changed slightly in version 1.2
 perhaps we're just paranoid).
Can you see a problem with the above code? Yes, if we're entering a
sequence of operations eg "3" * "4" + "5" then when we press "+" there
will be a cockup! Think about a fix for this when you look at the
following code:
JavaScript for Calculating results (On pressing the = button)

function Calculate() //PERFORM CALCULATION (= button)
{
if (Operation == 1) { Current = eval(Memory) * eval(Current); };
if (Operation == 2) { Current = eval(Memory) / eval(Current); };
if (Operation == 3) { Current = eval(Memory) + eval(Current); };
if (Operation == 4) { Current = eval(Memory)  eval(Current); };
Operation = 0; //clear operation
Memory = "0"; //clear memory
document.Calculator.Display.value = Current;
}

Simple, isn't it? Depending on the operation code, we multiply,
divide, add or subtract the number we stored in Memory and the Current
number. We use eval to turn the strings in Memory and
Current into respectable numbers. Can you see the obvious problems?
Here they are:
 We haven't trapped divide by zero;
 We aren't aware if a number grows too big or too small;
 We haven't accounted for the possibility that JavaScript might
occasionally return "NaN" (Not a number) when it gets confused!
 In addition, there's a rather subtle error.
What's the subtle error? Well, if you actually make the calculator (or
use our example at the start of this document, which sorts out most of
the above problems) you'll see that, after you've performed an operation,
you can alter the number (result) that appears on the Display. (This is
unlike most conventional calculators!) What is really interesting is
that with the above code a JavaScript error results when you
press the +/ button immediately after calculating a result! Can you
see why?
The answer is in the weak typing of JavaScript. When we say:
Current = eval(Memory) * eval(Current);
we are actually changing Current from a string to a number!
Can you think of a way to get it back to a string again?
JavaScript for FixCurrent

function FixCurrent()
{
Current = document.Calculator.Display.value;
Current = "" + parseFloat(Current);
if (Current.indexOf("NaN") != 1)
{ Current = "Aargh! I don't understand";
};
document.Calculator.Display.value = Current;
}

Finally, we need to handle all the complex things that might
be typed by the user in the display area (which we've conveniently
left accessible  how would you disable it?).
We use the tricksy builtin JavaScript function parseFloat
to see whether the stuff typed in made sense. See how we convert
the resulting number to a string by simply adding a null string (The
answer to one of my questions above).
Clearly the above functions are only rough drafts. It is however easy
to see the actual code that resulted in our simple calculator. Just
click View and then Page Source (or the equivalent) on your browser!
This calculator is by no means perfect. See how many errors you
can find! (There are no prizes, but we'd appreciate
an email if you find something
gross). You can have even more fun (if this is the sort of thing
that turns you on) by trying to crash the numerous JavaScript Calculators
you'll find on the web.