Hey guys in this post, we will create a simple Javascript Tip Calculator. Follow this tutorial, we will create the project step by step. The project is already live on the internet, you can click here to see the final version of the application.
Table of Contents
Topics covered
This application involves the following topics –
- DOM Manipulation
- Control Structures
- Array.forEach()
- JavaScript CSS Manipulation
- eventListeners
- setTimeout()
- Immediately Invoked Function Expressions
Complete source code
The below image shows you the project structure –
Add styles to the application
Create a main.css
file and add the following content –
.max-height {
min-height: 100vh;
}
:root {
--lightBlue: #86bbd8;
--darkBlue: #336699;
--mainWhite: #f5f5f5;
--mainDark: #333333;
}
body {
background: var(--lightBlue);
}
.card-title {
background: var(--darkBlue);
border-top-right-radius: 0.5rem;
border-top-left-radius: 0.5rem;
color: var(--mainWhite);
}
.card {
border: none !important;
border-radius: 0.5rem !important;
}
.bill-icon,
.user-icon {
background: var(--darkBlue) !important;
color: var(--mainWhite);
}
.submitBtn {
background: var(--darkBlue);
font-size: 1.2rem;
color: var(--mainWhite);
}
.submitBtn:hover {
background: var(--lightBlue);
color: var(--mainDark);
}
/* feedback */
.feedback {
display: none;
}
.loader {
display: none;
}
.results {
display: none;
}
.showItem {
display: block;
}
Add scripts to the application
Create an app.js
file and add the following content –
(function(){
//Set up a service array
const services = [{
value: 1,
title: "great - 20%"
},{
value: 2,
title: "good - 10%"
},{
value: 3,
title: "bad - 2%"
}]
const validateInput = function(billAmount, numUsers, selectedService){
let isFeedback = false;
const feedback = document.querySelector('.feedback');
feedback.innerHTML = '';
if (billAmount === "" || billAmount <="0"){
feedback.classList.add('showItem', 'alert-danger');
feedback.innerHTML += `<p>Bill amount cannot be blank</p>`
isFeedback = true;
}
if (numUsers <= "0"){
feedback.classList.add('showItem', 'alert-danger');
feedback.innerHTML += `<p>Number of users must be greater than zero</p>`;
isFeedback = true;
}
if (selectedService === "0"){
feedback.classList.add('showItem', 'alert-danger');
feedback.innerHTML += `<p>You must select a Service</p>`
isFeedback = true;
}
setTimeout(function(){
feedback.classList.remove('showItem', 'alert-danger');
}, 10000);
return isFeedback;
}; // end validateInput
const calculateTip = function(billAmount, numUsers, selectedService) {
let percentTip = '';
if (selectedService === "1"){
percentTip = 0.2;
} else if (selectedService === "2"){
percentTip = 0.1;
} else {
percentTip = 0.02;
}
const tipAmount = Number(billAmount)*percentTip;
const totalAmount = Number(billAmount) + Number(tipAmount);
const eachPerson = Number(totalAmount) / Number(numUsers);
return [tipAmount, totalAmount, eachPerson];
};
//FORM SETUP - ADD SERVICES
services.forEach(function(service){
//create the option element
const option = document.createElement('option');
option.textContent = service.title;
option.value = service.value;
//select the select element from the DOM
const select = document.querySelector('#input-service');
select.appendChild(option);
})
//FORM SETUP - ADD EVENT LISTENER AND FUNCTION CALLS
const inputForm = document.querySelector('form');
inputForm.addEventListener('submit', function(e){
e.preventDefault();
//grab elements from the DOM
const inputBill = document.querySelector('#input-bill');
const inputUsers = document.querySelector('#input-users');
const serviceValue = document.querySelector('#input-service');
//get values from DOM elements
let billAmount = inputBill.value;
let numUsers = inputUsers.value;
let selectedService = serviceValue.value;
//get feedback if info is not validated
const isFeedback = validateInput(billAmount, numUsers, selectedService);
//calculated tip if info was validated
if (!isFeedback){
const loader = document.querySelector('.loader');
const resultsDOM = document.querySelector('.results');
const tipResultsDOM = document.querySelector('#tip-amount');
const totalAmountDOM = document.querySelector('#total-amount');
const eachPersonDOM = document.querySelector('#person-amount');
//calculate results
const results = calculateTip(billAmount, numUsers, selectedService);
//show loader
loader.classList.add('showItem');
// show results after 2 seconds
setTimeout(function(){
loader.classList.remove('showItem');
tipResultsDOM.textContent= `${results[0].toFixed(2)}`
totalAmountDOM.textContent= `${results[1].toFixed(2)}`
eachPersonDOM.textContent= `${results[2].toFixed(2)}`
resultsDOM.classList.add('showItem');
},2000)
//clear values from DOM elements after 5 seconds
setTimeout(function(){
inputBill.value = '';
inputUsers.value = '';
serviceValue.value = 0;
resultsDOM.classList.remove('showItem');
}, 10000)
} //end isFeedback statement
}); //end eventListener for form
})();
Add HTML to the application
Create an index.html
file and add the following content –
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- bootstrap css -->
<link rel="stylesheet" href="./css/bootstrap.min.css">
<!-- main css -->
<link rel="stylesheet" href="./css/main.css">
<!-- google fonts -->
<link href="https://fonts.googleapis.com/css?family=Courgette" rel="stylesheet">
<!-- font awesome -->
<link rel="stylesheet" href="./css/all.css">
<title>Background Image Project</title>
<style>
</style>
</head>
<body>
<div class="container">
<div class="row max-height align-items-center">
<div class="col-10 mx-auto col-md-8">
<div class="card">
<div class="card-title p-2">
<h3 class="text-uppercase text-center">tip calculator</h3>
</div>
<div class="card-body">
<!-- end of card title -->
<div class="feedback text-center alert text-capitalize p-1">
your feedback
</div>
<form id='tip-form'>
<!-- single input -->
<div class="my-4">
<h5 class="text-capitalize mb-2">how much was your bill ?</h5>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text bill-icon"><i
class="fas fa-dollar-sign fa-fw"></i></span>
</div>
<input type="number" class="form-control form-control-lg" id="input-bill"
step=".01">
</div>
</div>
<!-- end of single input -->
<!-- single input -->
<div class="my-4">
<h5 class="text-capitalize mb-2">how many people sharing the bill ?</h5>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text user-icon"><i
class="fas fa-user fa-fw"></i></span>
</div>
<input type="number" class="form-control form-control-lg" id="input-users">
</div>
</div>
<!-- end of single input -->
<!-- single input -->
<div class="my-4">
<h5 class="text-capitalize mb-2">how was your service</h5>
<div class="form-group">
<select class="form-control form-control-lg text-capitalize" id="input-service">
<option selected value="0">Choose...</option>
</select>
</div>
</div>
<!-- end of single input -->
<input type="submit" class="d-block mx-auto text-capitalize btn submitBtn w-75"
value="calculate">
</form>
<div class="loader text-center">
<img src="img/Facebook-1s-200px.gif" alt="">
</div>
<!-- results -->
<div class="results text-center my-3">
<h3 class="text-capitalize">tip amount<span> $ </span><span id="tip-amount"></span></h3>
<h3 class="text-capitalize">total amount<span> $ </span><span id="total-amount"></span></h3>
<h3 class="text-capitalize">each person owes<span> $ </span><span id="person-amount"></span>
</h3>
</div>
</div>
<!-- -->
</div>
</div>
</div>
</div>
<!-- jquery -->
<script src="./js/jquery-3.3.1.min.js"></script>
<!-- bootstrap js -->
<script src="./js/bootstrap.bundle.min.js"></script>
<!-- script js -->
<script src="./js/app.js"></script>
</body>
</html>
Screenshots
Note: Make sure to download the bootstrap.css, bootstrap.js, and jquery.js library from the internet add them to the respective folders. You can download the images from the Github repository.
Download the complete source code from github repository
Original source https://jsbeginners.com/tip-form-javascript-project/