Home > Software engineering >  Tip calculator javascript
Tip calculator javascript

Time:11-26

I am creating a tip calculator which calculates tip amount based on bill amount, tip percentage, and the number of people (which are all inputs by the user). I have created a script using Javascript but it's not working and I am not sure why. Am I calling the function in the wrong way? Did I make any mistakes in the function or in the for loop? I apologize for the messed-up layout of the calculator in the snippet, I am going with a mobile-first approach and still working on the desktop layout.

let allButtons = document.getElementsByClassName('btn');
let noOfButtons = allButtons.length;
let i;

function tipCalculate(e) {
  let billAmount = parseFloat(document.getElementById('bill__amount').value);
  let tipPercent = e.target.value;
  let noOfPeople = document.getElementById('people-no').value;
  let tipAmountPerPerson = billAmount / 100 * tipPercent / noOfPeople;
  let totalAmountPerPerson = (billAmount   (billAmount / 100 * tipPercent)) / noOfPeople;
  document.getElementByClassName('tip-amount-display').innerHTML = tipAmountPerPerson;
  document.getElementByClassName('total-amount-display').innerHTML = totalAmountPerPerson;
}

// append event listeners to each button
for (i = 0; i < noOfButtons; i  ) {
  allButtons[i].addEventListener('click', tipCalculate);
}
@import url('https://fonts.googleapis.com/css2?family=Space Mono:wght@400;700&display=swap');
:root {
  --clr-primary: hsl(172, 67%, 45%);
  --clr-neutral-100: hsl(0, 0%, 100%);
  --clr-neutral-200: hsl(189, 41%, 97%);
  --clr-neutral-300: hsl(185, 41%, 84%);
  --clr-neutral-400: hsl(184, 14%, 56%);
  --clr-neutral-500: hsl(186, 14%, 43%);
  --clr-neutral-600: hsl(183, 100%, 15%);
}

*,
*::after,
*::before {
  box-sizing: border-box;
}

h2 {
  margin: 0;
  font-size: 1rem;
}

body {
  margin: 0;
  font-family: 'Space Mono', monospace;
  background: var(--clr-neutral-300);
  font-size: 1rem;
  font-weight: 400;
}

button {
  font-family: 'Space Mono', monospace;
  text-transform: uppercase;
  border: none;
  padding: 0.3em 0.6em;
  border-radius: 0.45rem;
  font-size: 1.4rem;
  font-weight: 700;
}

.btn-main {
  background-color: var(--clr-neutral-600);
  color: var(--clr-neutral-100);
}

.btn-main:hover,
.btn-main:focus {
  background-color: var(--clr-primary);
  color: var(--clr-neutral-600);
}

.btn-inverse {
  background-color: var(--clr-primary);
  color: var(--clr-neutral-600);
}

.title {
  color: var(--clr-neutral-500);
  text-align: center;
  letter-spacing: .35em;
  padding: 1em 0;
}

form {
  background: var(--clr-neutral-100);
  border-radius: 1.8rem 1.8rem 0 0;
}

.accent-title {
  color: var(--clr-neutral-500);
}

.accent-title-light {
  color: var(--clr-neutral-400);
  font-size: .8rem;
}

.tip-amount {
  background: var(--clr-neutral-600);
  border-radius: 1rem;
  padding: 1.6rem;
  display: flex;
  /* flex-direction: column; */
  flex-wrap: wrap;
  justify-content: space-between;
}

.neutral-title {
  color: var(--clr-neutral-100);
}

input {
  border: none;
  background-color: var(--clr-neutral-200);
  width: 100%;
  border-radius: .25rem;
}

.bill__amount,
.people-no {
  height: 40px;
  text-align: right;
  font-family: 'Space Mono', monospace;
  font-size: 24px;
  font-weight: 700;
  color: var(--clr-neutral-600);
  padding-right: .8rem;
}

.bill__amount {
  background-image: url(../images/icon-dollar.svg);
  background-repeat: no-repeat;
  background-position: left center;
  background-origin: content-box;
  padding-left: .8rem;
}

.people-no {
  background-image: url(../images/icon-person.svg);
  background-repeat: no-repeat;
  background-position: left center;
  background-origin: content-box;
  padding-left: .8rem;
}

div div {
  margin-top: 2em;
}

.calculator {
  padding: 2rem;
}

.tip__btns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.accent-title-light {
  margin-top: 0%;
}

.reset {
  width: 100%;
  margin-top: 1rem;
}

.tip__heading {
  margin-bottom: .9rem;
}

.tip__custom {
  font-family: 'Space Mono', monospace;
  font-size: 1.3rem;
  font-weight: 700;
  letter-spacing: .1rem;
  text-align: right;
  padding-right: .8rem;
}

.bill__heading,
.no-of-people__heading {
  margin-bottom: .6rem;
}

.tip-amount-display,
.total-amount-display {
  /* text-align: right; */
  color: var(--clr-primary);
  font-size: 24px;
}

.total-amount-display {
  margin-top: 1.25rem;
}

.tip-amount-display {
  align-self: start;
  margin-top: .4rem;
}

.col .col {
  margin-top: 0;
}

@media (min-width: 768px) {
  form {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    align-content: stretch;
    width: 50%;
    margin: 0 auto;
    border-radius: 1.8rem 1.8rem 1.8rem 1.8rem;
  }
  form>* {
    flex: 1 1 50%;
  }
  .attribution {
    align-self: flex-end;
  }
  div div {
    margin-top: 0;
  }
}

.attribution {
  font-size: 11px;
  text-align: center;
}

.attribution a {
  color: hsl(228, 45%, 44%);
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <!-- displays site properly based on user's device -->
  <link rel="stylesheet" href="css/style.css">
  <link rel="icon" type="image/png" sizes="32x32" href="./images/favicon-32x32.png">
  <script src="js/tip.js"></script>

  <title>Frontend Mentor | Tip calculator app</title>

</head>

<body>
  <h1 class="title">SPLI<br>TTER</h1>
  <form class="calculator">

    <div class="main-cols">
      <div class="bill">

        <h2 class="bill__heading"><label for="bill__amount" class="accent-title">Bill</label></h2>
        <input type="text" name="bill__amount" id="bill__amount" class="bill__amount" placeholder="0">

      </div>
      <div class="tip">

        <h2 class="tip__heading"><label for="" class="accent-title">Select Tip %</label></h2>
        <div class="tip__btns">
          <button type="button" class="btn btn-main">5%</button>
          <button type="button" class="btn btn-main">10%</button>
          <button type="button" class="btn btn-main">15%</button>
          <button type="button" class="btn btn-main">25%</button>
          <button type="button" class="btn btn-main">50%</button>
          <input type="text" name="tip__custom" class="tip__custom" id="tip__custom" placeholder="Custom">
        </div>
      </div>

      <div class="no-of-people">
        <h2 class="no-of-people__heading"><label for="people-no" class="accent-title">Number of People</label></h2>
        <input type="text" name="people-no" id="people-no" class="people-no" placeholder="0">
      </div>
    </div>

    <div class="main-cols">
      <div class="tip-amount">

        <div class="col">
          <h2 class="neutral-title">Tip Amount</h2>
          <h3 class="accent-title-light ">/ person</h3>
          <h2 class="neutral-title">Total</h2>
          <h3 class="accent-title-light">/ person</h3>
        </div>
        <div class="col">
          <h2 class="tip-amount-display">$0.00</h2>
          <h2 class="total-amount-display">$0.00</h2>
        </div>
        <button class="btn-inverse reset">Reset</button>
      </div>
    </div>

    <div class="attribution">
      Challenge by <a href="https://www.frontendmentor.io?ref=challenge" target="_blank">Frontend Mentor</a>. Coded by <a href="#">Sachin Jadhav</a>.
    </div>
  </form>


</body>

</html>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

Issue 1

It's getElementsByClassName not getElementByClassName (you are missing the 's'). Here is how to use it: https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName

Specifically document.getElementsByClassName('test')[0] will be of interest for you, to get the first element with that class.

Your code will look like this:

document.getElementsByClassName('tip-amount-display')[0].innerHTML = tipAmountPerPerson;
//                 ^                                 ^

Alternatively you can use querySelector to find an element in the DOM using css selectors.

Issue 2.1

e.target.value is always an empty string (doing math with it will result in NaN). This is because the HTML Element that was clicked did not have a value property on it. To fix it add value="5" to the Buttons in your HTML like this:

<button type="button" value="5" class="btn btn-main">5%</button>
<button type="button" value="10" class="btn btn-main">10%</button>
<!-- ... -->

Issue 2.2

document.getElementById('people-no').value is also an empty string when no value was entered. To fix it you can check for it's truthiness as the empty string and 0 will be falsy you can replace them with 1.

Long version:

let noOfPeople = document.getElementById('people-no').value;
  if (!noOfPeople) {
    noOfPeople = 1;
  }

Short version using short circuit evaluation:

let noOfPeople = document.getElementById('people-no').value || 1;

Here is a working fiddle: https://jsfiddle.net/zg6t4o1a/

  • Related