I have started to learn JavaScript over the last few weeks. I have gone through most of the Head First JavaScript Programming book and it has been fantastic. I highly recommend it!
Anyways, I found a cool little project that I wanted to attempt to make a script for. After a few hours of learning, adding and bug squashing, I have a working script.
Airflow Calculator:
Test Values:
Area: 150
Ceiling Height: 2.7
Adjustment Factor: 1
Unit: D095
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<script>
//Air Changes Calculator
function init() {
// Set the User Variables
var unit = ["D095", "D125", "D160", "D195", "D230", "D255", "C125", "C160", "C205", "C240"];
var m3 = [7500, 10000, 12500, 15000, 18000, 19500, 10000, 12500, 16000, 18500];
var webPrint = document.getElementById("output");
var reccommended = document.getElementById("reccommended");
var floorArea = document.getElementById("floorarea").value;
var ceilingHeight = document.getElementById("ceilingheight").value;
var adjustmentFactor = document.getElementById("adjustment").value;
var unitAir;
var volume = floorArea * ceilingHeight;
var adjustedVolume = volume * adjustmentFactor;
var unitSelection = document.getElementById("model").value;
for (var i = 0; i < unit.length; i++) {
if (unit[i] === unitSelection) {
unitAir = m3[i];
}
}
var calc = unitAir / adjustedVolume;
webPrint.innerHTML = "For a " + floorArea + " m2 area, The "
+ unitSelection + " will provide " + Math.round(calc) + " air changes.";
// Function 2 - Get any unit that provides between 30 - 40 air changes for that area and adjustment factor
var firstResult = 0
for (var i = 0; i < unit.length; i++) {
var suggestResult = m3[i] / adjustedVolume;
// console.log(i);
if ((suggestResult > 30 && suggestResult < 40 && firstResult == 0)) {
var text;
text = "We can also reccommend the " + unit[i] + " as it will give " + Math.round(suggestResult) + " air changes <br/>";
document.getElementById("reccommended").innerHTML = text;
// console.log("We are inside the TRUE");
firstResult++
} else if ((suggestResult > 30 && suggestResult < 40)) {
var text;
text += "We can also reccommend the " + unit[i] + " as it will give " + Math.round(suggestResult) + " air changes <br/>";
// console.log("We are inside the FALSE");
}
//console.log("This is the Result: " + firstResult);
}
document.getElementById("reccommended").innerHTML = text;
}
</script>
</head>
<body>
<form>
Enter Floor Area: <input type="text" name="floorarea" id="floorarea"></br></br>
Enter Ceiling Height: <input type="text" name="ceilingheight" id="ceilingheight"></br></br>
Enter Adjustment Factor (Min 1): <input type="text" name="adjustment" id="adjustment"></br></br>
Enter Unit Model: <input type="text" name="model" id="model"></br></br>
<input type="button" value="Submit" onclick="init()">
</form>
<p id="output"></p>
<h2>Recommended Units:</h2>
<p id="reccommended"></p>
</body>
</html>
Can I make this any simpler? Is there anything I have missed or gone a long way around with?
Advancing from here, how can I have the values in an object, and then look-up the object as per my current script? Is this possible or do I need an array for both 'Unit' and 'M3'?
My next step after that would be to have it connect to an XML or JSON document and retrieve the values from there and also to have error checking on each field.
3 Answers 3
Nice question, from a once over:
- You do not need both
id
andname
- As mentioned by others, simply use
<br>
instead of <\br> - You can avoid the double
<br>
by adding a margin to to the input boxes with a style:input { margin-bottom: 20px }
- You are missing a ton of semicolons
- JsHint finds a lot of things to improve in general
- Always clean out uncommented code
- Instead of using
Math.round
when you are concatenating the strings, you could have done this once in thevar
declaration:
var suggestResult = Math.round( m3[i] / adjustedVolume );
- You conflate
model
andunit
a number of times, I would drop the notion of unit for model in this exercise. A unit is 1 tangible unit, a model is not. - As an other reviewer pointed out, the text input for the model should really be a dropdown.
I created a counter suggestion, with 1 big piece missing ( excercise for the reader :) , the 2 arrays should be 1 array of objects which contain model
and capacity
. To compensate for that I provided some code to create a dropdown from you ;)
// Set the Air Units
var models = ["D095", "D125", "D160", "D195", "D230", "D255", "C125", "C160", "C205", "C240"];
var capacities = [7500, 10000, 12500, 15000, 18000, 19500, 10000, 12500, 16000, 18500];
//Air Changes Calculator
function calculate() {
var webPrint = document.getElementById("output"),
recommended = document.getElementById("recommended");
var floorArea = document.getElementById("floorarea").value,
ceilingHeight = document.getElementById("ceilingheight").value,
adjustmentFactor = document.getElementById("adjustment").value,
modelSelection = document.getElementById("model").value;
var modelCapacity;
for (var i = 0; i < models.length; i++) {
if (models[i] === modelSelection) {
modelCapacity = capacities[i];
}
}
var volume = floorArea * ceilingHeight,
adjustedVolume = volume * adjustmentFactor,
calc = Math.round( modelCapacity / adjustedVolume );
webPrint.innerHTML = "For a " + floorArea + " m2 area, The " +
modelSelection + " will provide " + calc + " air changes.";
// Function 2 - Get any unit that provides between 30 - 40 air changes for that area and adjustment factor
var text = '';
for (i = 0; i < models.length; i++) {
var suggestResult = Math.round( capacities[i] / adjustedVolume );
if ((suggestResult > 30 && suggestResult < 40)) {
text += "We can also recommend the " + models[i] +
" as it will give " + suggestResult + " air changes <br/>";
}
}
recommended.innerHTML = text;
}
function replaceWithDropdown( id , valueList ){
var element = document.getElementById( id ),
dropdown = document.createElement("select"),
value = element.value,
option;
dropdown.id = id;
for( var i = 0 ; i < valueList.length ; i++ ){
option = document.createElement("option");
option.text = valueList[i];
option.value = valueList[i];
if( option.value == value){
option.selected = true;
}
dropdown.options.add(option);
}
element.parentNode.replaceChild( dropdown , element );
}
replaceWithDropdown( "model" , models );
input { margin-bottom: 20px }
<form>
Enter Floor Area:
<input type="text" id="floorarea" value="150"><br>
Enter Ceiling Height:
<input type="text" id="ceilingheight" value="2.7"><br>
Enter Adjustment Factor (Min 1):
<input type="text" id="adjustment" value="1"><br>
Enter Unit Model:
<input type="text" id="model" value="C160"><br>
<input type="button" value="Submit" onclick="calculate()">
</form>
<p id="output"></p>
<h2>Recommended Units:</h2>
<p id="recommended"></p>
As per your question, you can create an array of both pieces of info like this:
var models = [
{ name : "D095" , capacity : 7500 },
{ name : "D125" , capacity : 10000 },
{ name : "D195" , capacity : 12500},
//etcetera etcetera
];
This is of course a bit repetitive, so you could DRY this by creating a helper function
function model( name , capacity){
return {
name: name,
capacity: capacity
}
}
var models = [
model( "D095" , 7500 },
model( "D125" , 10000 },
model( "D195" , 12500 },
//etcetera etcetera
];
-
\$\begingroup\$ Awesome! Thank you for the great suggestions. It seems my code is workable, it is just the 'cleaning up' that I need to work on. Thank you for you JSfiddle link. Very helpful for someone new to JS. Two questions, in the calculate function, do we not need to declare 'var' for each varaible? Why did you do this? Also - How can you make an array with both 'model' and 'modelcapacity' and then reference it in the code? \$\endgroup\$Jimmy P– Jimmy P2014年11月10日 20:43:29 +00:00Commented Nov 10, 2014 at 20:43
-
\$\begingroup\$ Each variable needs to be declared with
var
to prevent global namespace pollution. That is a big deal. As for the array, I will give a hint in the answer. \$\endgroup\$konijn– konijn2014年11月10日 21:28:15 +00:00Commented Nov 10, 2014 at 21:28 -
\$\begingroup\$ Excellent. Thank for for the tip. I will look into this and figure how it works. I did not pick up that you used a ',' when declaring the vars so you did not need to keep typing 'var' next to each variable until you got to the last one and used ';'. I have made a lot of edits to the code to clean it up and add some error checking. Thank you very much for the assistance! \$\endgroup\$Jimmy P– Jimmy P2014年11月10日 21:38:56 +00:00Commented Nov 10, 2014 at 21:38
-
\$\begingroup\$ Well, It took me a while, but I finally understand the helper function. I had not dealt with these before. For anyone that was wondering, I was editing the code and changing:
models[i]
tomodels.name[i]
instead ofmodels[i].name
Great stuff. I have updated the main post with my edited code. I still have not done the dropdown as I will figure out exactly what that code does at a later time. \$\endgroup\$Jimmy P– Jimmy P2014年11月10日 22:40:34 +00:00Commented Nov 10, 2014 at 22:40
The misspelling of reccommended
is a trap for future maintenance. (You spelled it correctly in the <h2>
.)
The HTML fails to validate. It is a good idea to run your HTML through a validator, which would have told you that
- The
<head>
is missing a<title>
tag. - There is no such thing as a
</br>
tag — you probably meant<br />
, but<br>
would have sufficed.
It is not clear what measurements you expect. Metres? Feet? Feet and inches? (If so, will it accept 8 ft 2 in
or 8'2"
or some other format?) Putting "m2" after the text box would have eliminated this usability problem. (Use the <sup>
tag.)
The "Enter Unit Model" input should clearly be a drop-down selection instead of free-form text.
Since you are using HTML 5, you should use <input type="number">
. This gives a better user experience, particularly with Android, which will display a numeric keypad. (iOS is less helpful: is only shows a numeric keypad if you specify integer-only inputs using pattern="\d*".)
init()
is not the right name for your function. showRecommendations()
would be better.
-
\$\begingroup\$ Fantastic! Thank you. I never thought of running it through a markup validator. Very handy for future use. I have also separated the code into two functions plus an init() function to clean up the code. I am pretty happy with my first set of code in terms of the structure of the JS. Just some housekeeping issues! I hope to add some input error checking shortly too. \$\endgroup\$Jimmy P– Jimmy P2014年11月10日 01:18:13 +00:00Commented Nov 10, 2014 at 1:18
I'm far from a JS expert, but my 2 cents worth are as follows...
reccomend is incorrectly spelt everywhere.
use of 'magic numbers' - values such as 30, 40, m3 array, unit array etc. should be loaded from a database via ajax or the whole calculation done server side. Especially for a commercial environment, where these values would possibly change.
Other than that, looks good to me :-)