Now that the code is all working, that’s not the end of the process. We should leave the code better than we found it too.
We can use beautifier.io to clean up the formatting of the code, and then run the code through jslint.com to find obvious problems.
- Double quotes are preferred for strings instead of single quotes.
- Next is that out-of-scope code occurs. That is where a function is used before it is declared.
And JSLint is now happy with that code.
function calcVat(amount) {
return amount * 0.20;
}
function total() {
var vat = calcVat(addSum.innerText);
numVat.innerText = Number(vat).toFixed(2);
var three = parseFloat(addSum.innerText) || 0;
var four = parseFloat(numVat.innerText) || 0;
numTotal.innerText = Number(three + four).toFixed(2);
}
function add() {
var one = parseFloat(numOne.value) || 0;
var two = parseFloat(numTwo.value) || 0;
addSum.innerText = one + two;
total();
}
var numOne = document.getElementById("num-one");
var numTwo = document.getElementById("num-two");
var addSum = document.getElementById("add-sum");
var numVat = document.getElementById("add-vat");
var numTotal = document.getElementById("total");
numOne.addEventListener("input", add);
numTwo.addEventListener("input", add);
That’s not the end though.
Function names should typically be in the form of verb-noun. For example, getVat
, calcTotal
, addProducts
. So I’ll rename the functions to more closely follow those examples.
In the calcTotal function, the three
and four
variable names are quite terrible names. Instead of using those names, we can clarify at the start of the function that it is the sum and the vat that we are using.
function total() {
var sum = parseFloat(addSum.innerText);
var vat = calcVat(sum);
numVat.innerText = Number(vat).toFixed(2);
numTotal.innerText = Number(sum + vat).toFixed(2);
}
Also, it causes more problems when functions reach out to change other things. To avoid those troubles, its best if the functions receive information as arguments to the function.
function calcTotal(sumEl, vatEl, totalEl) {
var sum = parseFloat(sumEl.innerText);
var vat = calcVat(sum);
vatEl.innerText = Number(vat).toFixed(2);
totalEl.innerText = Number(sum + vat).toFixed(2);
}
function addProducts() {
...
calcTotal(addSum, numVat, numTotal);
}
The total function is now easily seen to do three big things. One is to get the values from the elements, one is to calculate the total, and the other is to update the totals. Functions tend to be more stable when you separate those different things out to separate functions.
I don’t want a separate function to update each value though, as that seems overboard. Instead I’ll use a function that receives two arguments - the place to update and the value to update it with. I’ve called it updateDollarText
to help make it clear that it’s showing values to two decimal places.
function updateDollarText(value, el) {
el.innerText = Number(value).toFixed(2);
}
function calcTotal(sumEl, vatEl, totalEl) {
var sum = parseFloat(sumEl.innerText);
var vat = calcVat(sum);
updateDollarText(vat, vatEl);
updateDollarText(sum + vat, totalEl);
}
The addProducts function is where the last of our cleanup takes place.
function addProducts() {
var one = parseFloat(numOne.value) || 0;
var two = parseFloat(numTwo.value) || 0;
addSum.innerText = one + two;
calcTotal(addSum, numVat, numTotal);
}
The one and two variables can be renamed to be more clear to price1
and price2
.
function addProducts() {
var price1 = parseFloat(numOne.value) || 0;
var price2 = parseFloat(numTwo.value) || 0;
addSum.innerText = price1 + price2;
calcTotal(addSum, numVat, numTotal);
}
We can also use updateDollarText on the sum.
// addSum.innerText = price1 + price2;
updateDollarText(one + two, addSum);
When we add the products, there are three main things that get done. One is to update the exVat total, one is to update the vat total, and the other is the update the overall total.
Because that’s how we think about things, it helps if the code matches how we think about things. The addProducts function should only have three functions calls, that each match those described activities.
Here’s the updated code for updating the exVat total.
function getFieldPrice(inputField) {
return parseFloat(inputField.value) || 0;
}
function updateExVat(price1Field, price2Field, exVatEl) {
var price1 = getFieldPrice(price1Field);
var price2 = getFieldPrice(price2Field);
updateDollarText(price1 + price2, exVatEl);
}
function addProducts() {
updateExVat(numOne, numTwo, addSum);
...
}
Here is the code for updating the vat
function getElPrice(el) {
return parseFloat(el.innerText) || 0;
}
function updateVat(exVatEl, vatEl) {
var sum = getElPrice(exVatEl);
var vat = calcVat(sum);
updateDollarText(vat, vatEl);
}
And lastly, calcTotal we’ll replace with being updateTotal.
function updateTotal(sumEl, vatEl, totalEl) {
var exVat = getElPrice(sumEl);
var vat = getElPrice(vatEl);
updateDollarText(exVat + vat, totalEl);
}
That leaves us with a much updated and cleaner addProducts function:
function addProducts() {
updateExVat(numOne, numTwo, addSum);
updateVat(addSum, numVat);
updateTotal(addSum, numVat, numTotal);
}
Here is the fully updated code, that takes care of things in as simple as practical a manner.
var numOne = document.getElementById("num-one");
var numTwo = document.getElementById("num-two");
var addSum = document.getElementById("add-sum");
var numVat = document.getElementById("add-vat");
var numTotal = document.getElementById("total");
function getFieldPrice(inputField) {
return parseFloat(inputField.value) || 0;
}
function getElPrice(el) {
return parseFloat(el.innerText) || 0;
}
function updateDollarText(value, el) {
el.innerText = Number(value).toFixed(2);
}
function updateExVat(price1Field, price2Field, exVatEl) {
var price1 = getFieldPrice(price1Field);
var price2 = getFieldPrice(price2Field);
updateDollarText(price1 + price2, exVatEl);
}
function calcVat(amount) {
return amount * 0.20;
}
function updateVat(exVatEl, vatEl) {
var sum = getElPrice(exVatEl);
var vat = calcVat(sum);
updateDollarText(vat, vatEl);
}
function updateTotal(sumEl, vatEl, totalEl) {
var exVat = getElPrice(sumEl);
var vat = getElPrice(vatEl);
updateDollarText(exVat + vat, totalEl);
}
function addProducts() {
updateExVat(numOne, numTwo, addSum);
updateVat(addSum, numVat);
updateTotal(addSum, numVat, numTotal);
}
numOne.addEventListener("input", addProducts);
numTwo.addEventListener("input", addProducts);
The main benefit here is that each function is nice and simple, easy to understand, and easy to update when additional features are required.