Build a Cash Register Project

I need some help with the project.
Tell me please , why my “cash” variable doesn’t show user input value? When I log it I get an empty object {}

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width; initial-scale=1.0">
    <link rel= "stylesheet" href="styles.css">
    <title>register</title>
  </head>
  <body>
    <p id="change-due"></p>
    <label for="cash">Money given:</label>
    <input id="cash" type="text">
    <button type="button" id="purchase-btn">Sell</button>
    <div id="cash-in-drawer"></div>
    <script src="script.js"></script>
  </body>
</html>

JS

let price = 1.87;
let cid = [
  ['PENNY', 1.01],
  ['NICKEL', 2.05],
  ['DIME', 3.1],
  ['QUARTER', 4.25],
  ['ONE', 90],
  ['FIVE', 55],
  ['TEN', 20], 
  ['TWENTY', 60],
  ['ONE HUNDRED', 100]
];
const currencyKey = [
  ['ONE HUNDRED', 100],
  ['TWENTY', 20],
  ['TEN', 10],
  ['FIVE', 5],
  ['ONE', 1],
  ['QUARTER', 0.25],
  ['DIME', 0.1],
  ['NICKEL', 0.05],
  ['PENNY', 0.01],
]
const dic = cid.reverse();
const cash = document.getElementById("cash").value;
const button = document.getElementById("purchase-btn");
const changeDue = document.getElementById("change-due");
const cashInDrawer = document.getElementById("cash-in-drawer");
cashInDrawer.textContent = dic;
const cashMinusPrice = cash.textContent - price;
let change = [];
const sale = (arr) => {
  for (let i = 0; i < arr.length; i++) {
    if (cashMinusPrice >= arr[i] && dic[i].value - arr[i].value >= 0) { 
change.push(dic[i].key);
change.push(Math.floor(dic[i].value / cashMinusPrice));
return result;
    }
  }
}
const sell = () => {
  sale(currencyKey);
  if (cash.value < price) {
    alert("Customer does not have enough money to purchase the item");
  } else if (cash.value === price) {
    changeDue.textContent = "No change due - customer paid with exact cash";
  }
  if (cashInDrawer.value < changeDue.value) {
    changeDue.textContent = "Status: INSUFFICIENT_FUNDS"
  }
  /*if (cashInDrawer.value === changeDue.value) {
    changeDue.textContent = "Status: CLOSED" 
  }*/
  if (cash.value > price) {
    changeDue.textContent = `Status: OPEN ${change}`
  }
}

button.addEventListener("click", sell);

console.log(change);
console.log(cashMinusPrice);
console.log(cash)

because this line const cash = document.getElementById("cash").value;
is in the global scope which is executed immediately after the page loads. So, its value is an empty string ''. Try in your console.log(cash) to see cash.length and it’s 0.

You can place it inside your sell function so that it will get the value only when the user clicks the button.


You’re using the cash variable in other places too like in cashMinusPrice variable.
You can leave cash as it is but remove .value so it will only reference to that input element and use it as you want.

for example, to get the user input in your sell function use
let user_input = cash.value;

Notice that your cashMinusPrice variable is also executed in the global scope so its value isn’t calculated when the user clicks the button.

Thank you, Mostafa, got it .
My code is really wet and haven’t finished yet, so there are a lot of bugs probably, right :sweat_smile:

Please, help me understand why I enter a number 1.89 and log the result (user_input - price), I get 0.019999999999999796 instead of 0.02?
When I enter 2.87 I get 1, that is right.
I’m confused :thinking:

let price = 1.87;
let cid = [
  ['PENNY', 1.01],
  ['NICKEL', 2.05],
  ['DIME', 3.1],
  ['QUARTER', 4.25],
  ['ONE', 90],
  ['FIVE', 55],
  ['TEN', 20], 
  ['TWENTY', 60],
  ['ONE HUNDRED', 100]
];
let change = [];
const currencyKey = [
  {key:'ONE HUNDRED', value: 100},
  {key: 'TWENTY', value: 20},
  {key: 'TEN', value: 10},
  {key: 'FIVE', value: 5},
  {key: 'ONE', value: 1},
  {key: 'QUARTER', value: 0.25},
  {key :'DIME', value: 0.1},
  {key: 'NICKEL', value: 0.05},
  {key: 'PENNY', value: 0.01},
]
const dic = cid.reverse();
const cash = document.getElementById("cash");
const button = document.getElementById("purchase-btn");
const changeDue = document.getElementById("change-due");
const cashInDrawer = document.getElementById("cash-in-drawer");
cashInDrawer.textContent = dic;

const sale = () => {
  let user_input = Number(cash.value);
  let result = "";
  const cashMinusPrice = () => {result = user_input - price;
  console.log(result);
  return result};
  cashMinusPrice();
  if (result > 0) {
  for (let i = 0; i < dic.length; i++) {
    if (result > currencyKey[i].value) {
      let calc = Math.floor(result / currencyKey[i].value);
      /*while (calc >= dic[i].value) {*/
change.push(currencyKey[i].key);
result -= calc * currencyKey[i].value;
change.push(calc);
/*dic[i][1] -= calc * result;
console.log(dic) weird calculatuon, should subtract the sum from the cash box*/;
changeDue.textContent+= change//};
    }
    }
  }
}
const sold = () => {
  let user_input = Number(cash.value);
  sale(currencyKey);
  if (user_input < price) {
    alert("Customer does not have enough money to purchase the item");
  } else if (user_input === price) {
    changeDue.textContent = "No change due - customer paid with exact cash";
  }
  if (cashInDrawer.value < changeDue.value) {
    changeDue.textContent = "Status: INSUFFICIENT_FUNDS"
  }
  if (user_input > price) {
    changeDue.textContent = `Status: OPEN ${change}`
  }
}

button.addEventListener("click", sold);

/* TODO:
1) where is 1 penny?;
2) change should look like some arrays;
3) need to be able to compare change due with the cash register box assets*/

It happens because of the floating-point precision error in JavaScript. For example:

console.log(0.1 + 0.2); // Expected 0.3, but outputs 0.30000000000000004
console.log(1.89 - 1.87); // Expected 0.02, but outputs 0.019999999999999796

floating-point numbers are represented in binary format which can cause some precision errors.


To avoid this error, you can use the .toFixed() method to round it to a fixed number of decimal digits.

Note that .toFixed() method will return the number as string. You can use Number() to deal with it as a number.

let n1 = 0.1;
let n2 = 0.2;
let sum = n1 + n2;
let fixed_sum = (n1 + n2).toFixed(2);
let fixed_number = Number(fixed_sum);

console.log(sum, typeof sum);                     // 0.30000000000000004 number
console.log(fixed_sum, typeof fixed_sum);         // 0.30 string
console.log(fixed_number, typeof fixed_number);   // 0.3 number

Another workaround is to deal with all values as integers and then divide them by 100.

For example:

let price = 187;
let value = 189;
let change = value - price;
console.log(change / 100);     // 0.02
1 Like

Thank you for your explanations :innocent:

1 Like

Please, help me to find out why I sometimes lose 1 penny?
For example, when the input_value is 1.89, I get the right change (penny $0.02) and result (0.02), if user_input is 1.88 I got no change (#change-due element is empty and logged result is (0.01), if user_input is 98.61, the change is (TWENTY: $80 TEN: $10 FIVE: $5 ONE: $1 QUARTER: $0.5 DIME: $0.2 PENNY: $0.03) and the result is 96.74 so 1 penny ($0.01) is lost…

let price = 1.87;
let cid = [
  {key: 'PENNY', value: 1.01},
  {key: 'NICKEL', value: 2.05},
  {key: 'DIME', value: 3.1},
  {key: 'QUARTER', value: 4.25},
  {key: 'ONE', value: 90},
  {key: 'FIVE', value: 55},
  {key: 'TEN', value: 20}, 
  {key: 'TWENTY', value: 60},
  {key: 'ONE HUNDRED', value:100}
];
let change = [];
let status = "";
const currencyKey = [
  {key:'ONE HUNDRED', value: 100},
  {key: 'TWENTY', value: 20},
  {key: 'TEN', value: 10},
  {key: 'FIVE', value: 5},
  {key: 'ONE', value: 1},
  {key: 'QUARTER', value: 0.25},
  {key :'DIME', value: 0.1},
  {key: 'NICKEL', value: 0.05},
  {key: 'PENNY', value: 0.01},
]
const dic = cid.reverse();
const cash = document.getElementById("cash");
const button = document.getElementById("purchase-btn");
const changeDue = document.getElementById("change-due");
const cashInDrawer = document.getElementById("cash-in-drawer");
cashInDrawer.textContent = dic;

const sale = () => {
  let user_input = Number(cash.value);
  let result = Number("");
  const cashMinusPrice = () => {result = (user_input - price).toFixed(2);
  console.log(result);
  return result};
  cashMinusPrice();
  if (result > 0) {
  for (let i = 0; i < dic.length; i++) {
      let calc = Math.floor(result / currencyKey[i].value);
        if (result > currencyKey[i].value) {
change +=`${currencyKey[i].key}: `;
result -= calc * currencyKey[i].value;
change += `\$${calc * currencyKey[i].value} `;
let rest = Number(dic[i].value - currencyKey[i].value * calc);

let str = String(change);
const regex = str.replaceAll(",", " ");
if (rest < 0) {
  changeDue.textContent = "Status: INSUFFICIENT FUNDS"
} else {
  changeDue.textContent = "Status: OPEN ";
changeDue.textContent += regex};

    }
  }
  }
}
const sold = () => {
  let user_input = Number(cash.value);
  sale(currencyKey);
  if (user_input < price) {
    alert("Customer does not have enough money to purchase the item");
  } else if (user_input === price) {
    changeDue.textContent = "No change due - customer paid with exact cash";
  }
  if (changeDue.value > cashInDrawer.value) {
    changeDue.textContent = "Status: INSUFFICIENT_FUNDS"
  }
}

button.addEventListener("click", sold);

I see you are using Math.floor in your code. This function will round floats down so you may lose money because of it.

Try to log the values that you are sending to Math.floor and see if that is the cause.

Thank you.
Right, this is the exact place where the error occures:

let calc = Math.floor(result / currencyKey[i].value);

Would you mind to give me a hint how to fix it? I have the following part of code above, but it doesn’t help, as we can see:

const cashMinusPrice = () => {
result = (user_input - price).toFixed(2);
return result
};
  cashMinusPrice();

I am not sure what values you logged but my guess is that instead of the ceil function you could just use the toFixed function to keep the accuracy you need?

If you need more help please give us more information. (Show us your logs)

1 Like

I logged RESULT after this part of the code :

let calc = Math.floor(result / currencyKey[i].value);

Here are my logs:

3.13
3.13
3.13
3.13
3.13
0.1299999999999999
0.1299999999999999
0.1299999999999999
0.1299999999999999
0.1299999999999999
0.029999999999999888
0.029999999999999888
0.029999999999999888
0.029999999999999888
0.029999999999999888
0.029999999999999888
0.029999999999999888
0.009999999999999887
0.009999999999999887
0.009999999999999887
0.009999999999999887
0.009999999999999887
0.009999999999999887
0.009999999999999887

I have no idea how to interpret them

I cannot tell what the inputs were from your log. If you need the value to be rounded up, you can use the Math.round.
(You need to look at the numbers you have and what you are getting from the division and figure out whether you should be rounding or fixing the decimals or even using Math.ceil.

1 Like

I tried to go another way and rewrited the code, but failed again.

Now my logics is to get a number of change due for each amount is to compare what number is bigger — available amount divided by currency amount or change due amount divided by the same divider and pick the least. But I got a problem — when I divide a number by a decimal fraction I get a negative result. Is there a way how to fix it?

let price = 1.87;
let cid = [
  {key: 'PENNY', value: 1.01},
  {key: 'NICKEL', value: 2.05},
  {key: 'DIME', value: 3.1},
  {key: 'QUARTER', value: 4.25},
  {key: 'ONE', value: 90},
  {key: 'FIVE', value: 55},
  {key: 'TEN', value: 20}, 
  {key: 'TWENTY', value: 60},
  {key: 'ONE HUNDRED', value: 100}
];
let change = [];
const currencyKey = [
{key:'ONE HUNDRED', value: 100},
{key: 'TWENTY', value: 20},
{key: 'TEN', value: 10},
{key: 'FIVE', value: 5},
{key: 'ONE', value: 1},
{key: 'QUARTER', value: 0.25},
{key :'DIME', value: 0.1},
{key: 'NICKEL', value: 0.05},
{key: 'PENNY', value: 0.01},
];

const dic = cid.reverse();
const cash = document.getElementById("cash");
const button = document.getElementById("purchase-btn");
const changeDue = document.getElementById("change-due");
const cashInDrawer = document.getElementById("cash-in-drawer");

let dicTotal = 0;// calc total sum in the drawer
for (let i = 0; i < dic.length; i++) {
  dicTotal += dic[i].value;
};

const sale = () => {
  let user_input = Number(cash.value);
  let result = Number("");
  const cashMinusPrice = () => {
    result = (user_input - price).toFixed(2);
    return result
    };
  
  cashMinusPrice();
  let resultNum = Number(result);

// if cash in the drawer is equal to change due
  if (dicTotal === resultNum) {
    for (let i = 0; i < dic.length; i++) {
      if (dic[i].value > 0) {
        change += `${dic[i].key}: `;
        change += `\$${dic[i].value} `;
    }
  }
    let str = String(change);
    let regex = str.replaceAll(",", " ");
    changeDue.textContent  = "Status: CLOSED ";
    changeDue.textContent += regex;
  } // if change is available (doesn't work from line 64 (variable e)
    else if (result > 0 && result < dicTotal) {
  for (let i = 0; i < dic.length; i++) {
    let d = (dic[i].value / currencyKey[i].value).toFixed(0);
    let e = (result / currencyKey[i].value).toFixed(0);
    let f = e > d ? d : e;
    let g = f * currencyKey[i].value;
    console.log(e);
    while (result - currencyKey[i].value >= 0 
&& dic[i].value - currencyKey[i].value >= 0  && result > 0) {
        result -= currencyKey[i].value;
        dic[i].value -= currencyKey[i].value;

        if (result > dic[i].value) {
          change +=`${currencyKey[i].key}: `;
          change += `\$${g} `;
          result -= plus; 
if (result == 0 && dicTotal > 0) {
                            let str = String(change);
                            let regex = str.replaceAll(",", " ");
                            
  changeDue.textContent = "Status: OPEN ";
  changeDue.textContent += regex;
                          
                            
}
 console.log(result)  ;       
} 
  else if (result < dic[i].value && result > currencyKey[i].value) {
    let a = dic[i].value / currencyKey[i].value;
    let b = Number(result / currencyKey[i].value).toFixed(2);
    let c = (a - b) * currencyKey[i].value; 
    result -= c;            
                          let str = String(change);
let regex = str.replaceAll(",", " ");

/*if (result > 0 && dicTotal > 0) {
changeDue.textContent = "Status: INSUFFICIENT_FUNDS";
} 
  else*/ if (result > 0 && dicTotal <= 0) {
  changeDue.textContent = "Status: CLOSED ";
  changeDue.textContent += regex;
} else if (result === 0 && dicTotal > 0) {
  changeDue.textContent = "Status: OPEN ";
  changeDue.textContent += regex;
       }
      } 
     }
    }
   }
}
const sold = () => {
  let user_input = Number(cash.value);
  sale(currencyKey);
  if (user_input < price) {
    alert("Customer does not have enough money to purchase the item");
  } else if (user_input === price) {
    changeDue.textContent = "No change due - customer paid with exact cash";
  }
}

button.addEventListener("click", sold);

What are the two numbers you are dividing?
Please log them and the result of the division.
Also please post the line of code that you are using for our convenience (the specific line that you are using to divide and the logs you wrote)

These should not be global variables

This project kills me. I keep trying different methods but no one works properly :face_with_peeking_eye::face_with_peeking_eye::face_with_peeking_eye:

Please, help me with the loop :pray: it stops after the first circle, I think because I use the wrong condition, but I have no idea how to rewrite it

const button = document.getElementById("purchase-btn");
function checkRegister() {
let price = 1.87;
let cid = [
  ['PENNY', 101],
  ['NICKEL', 205],
  ['DIME', 310],
  ['QUARTER', 425],
  ['ONE', 9000],
  ['FIVE', 5500],
  ['TEN', 2000], 
  ['TWENTY', 6000],
  ['ONE HUNDRED', 10000]
];
const changeDue = document.getElementById("change-due");
let change = {stat: "", changeRegex: ""};
let resultedArr = [
  ['ONE HUNDRED: $', 0],
  ['TWENTY: $', 0],
  ['TEN: $', 0],
  ['FIVE: $', 0],
  ['ONE: $', 0],
  ['QUARTER: $', 0],
  ['DIME: $', 0],
  ['NICKEL: $', 0],
  ['PENNY: $', 0],
];

const currencyKeyMult = [10000, 2000, 1000, 500, 100, 25, 10,5, 1,];
const dicMult = cid.reverse();
const cash = document.getElementById("cash");
let dicTotal = 0;
for (let i = 0; i < dicMult.length; i++) {
  dicTotal += dicMult[i][1];
};

  let user_input = Number(cash.value);
  let  result = ((user_input - price) * 100);
  const str = String(resultedArr);
  const regex = str.replaceAll(",", "");
 if (user_input < price) {
       alert("Customer does not have enough money to purchase the item");
         } else if (user_input === price) {
             changeDue.textContent = "No change due - customer paid with exact cash";
    } else {
  for (let i = 0; i < dicMult.length; i++) {
/*----->*/    while (dicMult[i][1] > 0) {/* This condition is wrong*/
       if(result - currencyKeyMult[i] >= 0) {
  resultedArr[i][1] += currencyKeyMult[i];
  result -= currencyKeyMult[i];
  dicMult[i][1] -= currencyKeyMult[i];
  } else {break;}
  console.log(resultedArr);
  if (result === 0) { break;}

  for (let i = 0; i <= resultedArr.length; i++) {
    if (resultedArr[i][1] !== 0) {
    resultedArr[i][1]  /= 100
    }
  }
  if (result !== 0) {
    change.stat = "Status: INSUFFICIENT_FUNDS";
    return change;
  } else if (result === 0 && dicTotal === (result / 100)) {
    change.stat = "CLOSED ";
    change.changeRegex = regex;
    return change;
  } else { 
    resultedArr = resultedArr.filter(e => e[1] !== 0);
    change.stat = "OPEN ";
    change.changeRegex = regex;
    return change;
    }
  }

  changeDue.textContent = change.stat;
  changeDue.textContent += change.changeRegex;
 }
}
}
button.addEventListener("click", checkRegister);
  


You haven’t said what you were trying to make the while loop do? I prefer that you just tell us rather than us guessing.

Oops, sorry.
The whole loop should check if there is any money of a specific nominal available. If so, it should check if result is bigger than one money item. If so, it should reduce the result and amount of money of the specific nominal by the amount of that money item and add this money item to a specific array, or skip this item if it is unavailable. After that, the next round of check should start.

What I got: the loop stops after the first round of positive check (for example, my input is five, I need to get $3.13 of change. The loop subtracts 1 from the $1 nominal, adds it value to resultedArr and stops)

This happens because you used return which exits the function.


I don’t think you need that if.


Also, you should divide the values in the resultedArr finally. You put it inside the loop which will divide the values on each iteration.

And for regex and str their values should be assigned after all work is done, instead of having their values at the beginning, since they depend on resultedArr which will be modified later.


For tests, cid and price should be global variables.

For the cid array you set the values manually after multiplying them but the tests will assign it the other values without multiplying for testing which you will need to multiply them dynamically in your code instead (You may encounter some precision errors).


Overall, your logic and conditions are correct, but pay attention to how and when things should get executed (there are more things you can fix).

Use console.log() to track the execution and the values, and it will help you identify where the error is.

1 Like

Thank you for such a detailed explanation! :heart: