So, I have been recently heavily focusing on Front-End, for data validation, showing errors etc. And a big thank you to CertainPerformance for many reviews hes done for me :)
I have created a Report template using handlebars
and a MySQL
database to store the data, using Node JS
to interact between the 2. I have now gained understanding how Node JS can interact with the front end, grab data and send it to a database.
I'd like to hear some reviews to my current code - front, and back end. For me, personally it works and I am extremely happy that I am able to create such thing, whereas before I never thought I could :D
Just want to hear some reviews - where I can improve, where I'm I lacking, what can be simplified etc..
Node JS
Note: this function is triggered at routing stage, I haven't included it here.
// 21-TEMP-01a
exports.TEMP01A21 = async function(req, res) {
// Array to store actual temperature
var actualTemp = [];
// Array to store minimum temperature
var minTemp = [];
// Array to store maximum temperature
var maxTemp = [];
// Array to store actual humidity
var actualHumid = [];
// Array to store minimum humidity
var minHumid = [];
// Array to store maximum humidity
var maxHumid = [];
// Get drying room names
var roomNames = [];
// Loop thorugh each req.body values
for(var key in req.body) {
// Store req.body key to value var
var value = req.body[key];
// For each key that starys with ActualTemp store into array
if(key.startsWith("actualtemp")) {
actualTemp.push(value);
}
// minTemp
if(key.startsWith("mintemp")) {
minTemp.push(value);
}
// maxTemp
if(key.startsWith("maxtemp")) {
maxTemp.push(value);
}
// actualHumidity
if(key.startsWith("actualhumid")) {
actualHumid.push(value);
}
// minHumidity
if(key.startsWith("minhumid")) {
minHumid.push(value);
}
// maxHumidity
if(key.startsWith("maxhumid")) {
maxHumid.push(value);
}
// Room Names
if(key.startsWith("dryingroom")) {
roomNames.push(value);
}
}
// Get todays date
var today = new Date();
// Format the date
var formatDay = today.toISOString().substring(0, 10);
// Create an array to create custom MySQL query
var values = [];
// For each temperature value, store its output to values array
for(var i = 0; i < actualTemp.length; i++) {
values.push([roomNames[i] , actualTemp[i],
minTemp[i], maxTemp[i],
actualHumid[i], minHumid[i],
maxHumid[i], formatDay,
res.locals.user.id]);
}
db.query("insert into 21TEMP01a (room_name, actual_temperature, min_temperature, max_temperature, actual_humidity, min_humidity, max_humidity, time, user) values ?", [values], (error, result) => {
if(error) {
console.log(error);
}
else{
res.redirect('/reports/daily');
}
});
}
Front-End
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
<div class="container mt-4">
<h3>Form:</h3>
<form id="form" class="mt-4 mb-4" action="/reports_send/21-TEMP-01a" method="POST">
<div style="border: 1px solid black; padding: 40px; border-radius: 25px;">
<h4>Select Room</h4>
<div id="RoomSelect">
<select id="RoomMenu" class="form-control mb-4">
<!-- Drying Room 1 -->
<option value="dry-1">Drying Room 1</option>
<!-- Drying Room 2 -->
<option value="dry-2">Drying Room 2</option>
<!-- Dry Store-->
<option value="dry-3">Dry Store</option>
</select>
</div>
<div id="RoomInputs">
<!-- Drying Room 1 -->
<div class="form-group" id="dry-1">
<!-- Title -->
<h4>Drying Room 1</h4>
<input type="hidden" name="dryingroom1" value="Drying Room 1">
<!-- All temperatures -->
<div class="temperatures">
<label>Temperature °C - <strong>Actual</strong></label>
<input type="number" class="form-control" name="actualtemp1" step=0.01>
<label>Temperature °C - <strong>Minimum</strong></label>
<input type="number" class="form-control" name="mintemp1" step=0.01>
<label>Temperature °C - <strong>Maximum</strong></label>
<input type="number" class="form-control" name="maxtemp1" step=0.01>
</div>
<br>
<br>
<!-- All humidity -->
<div class="humidity">
<label>Relative Humidity - <strong>Actual</strong></label>
<input type="number" class="form-control" name="actualhumid1">
<label>Relative Humidity - <strong>Minimum</strong></label>
<input type="number" class="form-control" name="minhumid1">
<label>Relative Humidity - <strong>Maximum</strong></label>
<input type="number" class="form-control" name="maxhumid1">
</div>
</div>
<!-- Drying Room 2 -->
<div class="form-group" id="dry-2">
<!-- Title -->
<h4>Drying Room 2</h4>
<input type="hidden" name="dryingroom2" value="Drying Room 2">
<!-- All temperatures -->
<div class="temperatures">
<label>Temperature °C - <strong>Actual</strong></label>
<input type="number" class="form-control" name="actualtemp2" step=0.01>
<label>Temperature °C - <strong>Minimum</strong></label>
<input type="number" class="form-control" name="mintemp2" step=0.01>
<label>Temperature °C - <strong>Maximum</strong></label>
<input type="number" class="form-control" name="maxtemp2" step=0.01>
</div>
<br>
<br>
<!-- All humidity -->
<div class="humidity">
<label>Relative Humidity - <strong>Actual</strong></label>
<input type="number" class="form-control" name="actualhumid2">
<label>Relative Humidity - <strong>Minimum</strong></label>
<input type="number" class="form-control" name="minhumid2">
<label>Relative Humidity - <strong>Maximum</strong></label>
<input type="number" class="form-control" name="maxhumid2">
</div>
</div>
<!-- Dry Store -->
<div class="form-group" id="dry-3">
<!-- Title -->
<h4>Dry Store</h4>
<input type="hidden" name="dryingroom3" value="Dry Store">
<!-- All temperatures -->
<div class="temperatures">
<label>Temperature °C - <strong>Actual</strong></label>
<input type="number" class="form-control" name="actualtemp3" step=0.01>
<label>Temperature °C - <strong>Minimum</strong></label>
<input type="number" class="form-control" name="mintemp3" step=0.01>
<label>Temperature °C - <strong>Maximum</strong></label>
<input type="number" class="form-control" name="maxtemp3" step=0.01>
</div>
<br>
<br>
<!-- All humidity -->
<div class="humidity">
<label>Relative Humidity - <strong>Actual</strong></label>
<input type="number" class="form-control" name="actualhumid3">
<label>Relative Humidity - <strong>Minimum</strong></label>
<input type="number" class="form-control" name="minhumid3">
<label>Relative Humidity - <strong>Maximum</strong></label>
<input type="number" class="form-control" name="maxhumid3">
</div>
</div>
<div id="errors" class="mt-2 alert alert-danger" style="opacity: 0; transition: all .5s;">
<p>Please complete all required fields</p>
</div>
<button id="submit-btn" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
</div>
<!-- Errors -->
<div id="myModal" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Targets not met</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>Some temperatures or humidity values have not met their targets.</p>
<p>- Re-check or continue submitting current data.</p>
</div>
<div class="modal-footer">
<button id="submit-email" type="button" class="btn btn-primary">Submit</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<script>
// Store DOM Strings
var DOMStrings = {
room_options: '#RoomMenu'
};
// On selected option, show specific div element
showActiveElement = () => {
for(const option of document.querySelector(DOMStrings.room_options).options) {
document.querySelector(`#${option.value}`).style.display = "none";
}
if(document.querySelector(DOMStrings.room_options).value === 'dry-1') {
document.querySelector('#dry-1').style.display = "block";
} else if (document.querySelector(DOMStrings.room_options).value === 'dry-2') {
document.querySelector('#dry-2').style.display = "block";
} else if (document.querySelector(DOMStrings.room_options).value === 'dry-3') {
document.querySelector('#dry-3').style.display = "block";
}
}
// Show selected div element from options
document.querySelector(DOMStrings.room_options).addEventListener('change', () => {
showActiveElement();
});
// Validate data
document.getElementById("form").addEventListener("submit", (e) => {
const inputs = document.querySelectorAll('#form input');
let bool;
// 1. Check if input fields are empty
const empty = [].filter.call(inputs, e => e.value === "");
let notEmpty;
if(empty.length === 0) {
notEmpty = true;
} else {
e.preventDefault();
document.getElementById('errors').style.opacity = 1;
empty.forEach(element => {
element.style.borderColor = "red";
element.placeholder = "Required";
element.addEventListener("input", (e) => {
if(element.value === "") {
bool = false;
element.style.borderColor = "red";
element.placeholder = "Required";
} else {
element.style.borderColor = "#fff";
}
const empty = [].filter.call(inputs, e => e.value === "");
if(empty.length === 0) {
document.getElementById('errors').style.opacity = 0;
} else {
document.getElementById('errors').style.opacity = 1;
}
});
});
}
// Validate Temperature and humidity values
if(notEmpty == true) {
for (var i = 0; i < inputs.length; i++) {
// Validate Temperatures for Drying room 1 & 2
if(inputs[i].name.match(/^(actual|min|max)-temp-(1|2)$/)) {
validateTempDryingRoom(parseFloat(inputs[i].value), inputs[i], e);
}
// Validate Humidity for Drying room 1 & 2
if(inputs[i].name.match(/^(actual|min|max)humid(1|2)$/)) {
validateHumidityDryingRoom(parseFloat(inputs[i].value), inputs[i], e);
}
// Validate Temp. for Dry Store
if(inputs[i].name.match(/^(actual|min|max)temp(3)$/)) {
validateTempDryStore(parseFloat(inputs[i].value), inputs[i], e);
}
// Validate humidity for Dry Store
if(inputs[i].name.match(/^(actual|min|max)humid(3)$/)) {
validateHumidityDryStore(parseFloat(inputs[i].value), inputs[i], e);
}
}
}
});
function validateTempDryingRoom(value, item, e) {
if(value < 39.4 || value > 49) {
e.preventDefault();
item.style.backgroundColor = 'red';
$("#myModal").modal();
} else {
item.style.backgroundColor = '#fff';
}
}
function validateHumidityDryingRoom(value, item ,e) {
if(value < 14 || value > 30) {
e.preventDefault();
item.style.backgroundColor = 'red';
$("#myModal").modal();
} else {
item.style.backgroundColor = '#fff';
}
}
function validateTempDryStore(value, item, e) {
if(value < 10 || value > 27.2) {
e.preventDefault();
item.style.backgroundColor = 'red';
$("#myModal").modal();
} else {
item.style.backgroundColor = '#fff';
}
}
function validateHumidityDryStore(value, item ,e) {
if(value < 40 || value > 70) {
e.preventDefault();
item.style.backgroundColor = 'red';
$("#myModal").modal();
} else {
item.style.backgroundColor = '#fff';
}
}
document.getElementById('submit-email').addEventListener('click', () => {
const form = document.getElementById('form');
form.submit();
});
// On load
window.onload = () => {
showActiveElement();
}
</script>