Cash Register Help

Hi All,

I’m working through the FreeCodeCamp cash register challenge at the moment. I haven’t actually gotten to the meat of the challenge yet as I’m still ironing out the functionality of the cash register itself. I’m running into a problem I can’t seem to solve.

Whenever first loading the page, you can currently enter an amount, delete, clear, next(to add to sale amount list) and then hit sale which will alert and open the cash register. You then click the open register to close and reset.

The problem starts here. After first use, you now have to either double click the next button, or use the sale button twice(the first will throw an alert for invalid $amount). I cannot for the life of me understand why this happens. I don’t see how anything has changed compared to he first run.

I have tried targeting all parts and tried rebuilding. No luck.

Thanks, MM

Hello,

First of all, the design is fantastic - the cash design, the layout of the buttons, and the interactive functionality, like the drawer opening! And of course, the Vault Tec details and colors are really outstanding. :hushed::ok_hand:

I’ve found the source of the issue regarding the invalid amount, but could you please explain how this app works? What is expected from the user? How does it receive input and process it? I believe that if you start explaining and take a closer look at your code, you’ll figure it out too. Let’s try this approach first.

Hi,

Thank you for your reply and feedback. Love to see someone saw the logo. I realised that I had not updated the codepen (have done now).

The keypad functionality was supposed to direct the user to putting in the correct format. Up to from $0.01 to $999.99. This should work as intended on the codepen now. However as stated before, I still need to enter amounts twice to get no error. Or click buttons twice to interact with the value on screen.

I don’t understand why when I can see the correct amount in the screen, sometimes it will validate and others it wont. The validation is run entirely off what is present in the userInput screen.

You’re welcome. The design is really good!

Can you please delete all of your regex and control statements?

When I delete them, everything works smoothly. After that, if you need, we can discuss how you can handle managing input in the right format. But first, what input do you need? What process will execute? Because all of it is related to your change payment calculations and display screens’ string format. Furthermore, you don’t need them at all; you can handle input just with a simple if statement. If the input includes a decimal separator '.' don’t accept more than two numbers, or if the decimal separator is already there, don’t accept more than one.:slightly_smiling_face:

I try to avoid using regex as much as possible because it’s quite dangerous. It involves unnecessary recursive functions or ReDos valnurability or applications that don’t work with a simple missed character… So, simply using if statements, in my opinion, more clear and simple and secure. :wink:

But of course you can try to handle with regex but you still need to simplfy your controls.

ok so I tried working through the buttons function to get rid of regex. I don’t know how to rid the last bit:

numbers.forEach((button) => {
    button.addEventListener("click", () => {
        if(
            !userInput.value &&
            button.innerHTML !== "00" &&
            button.innerHTML !== "."
        ) {
            userInput.value += button.innerHTML //1st digit 0-9
        } else if (
            userInput.value &&
            userInput.value !== "0" &&
            userInput.value.length < 3 &&
            !userInput.value.includes(".")
        ){
            userInput.value += button.innerHTML //up to additonal 2 digits or "."
        } else if (button.innerHTML === "." && !userInput.value.includes(".")) {
            userInput.value += button.innerHTML //additonal "." if max 3 digits 0-9
        } else if (
            //cannot figure out how to allow only 2 digits after decimal without regex
            button.innerHTML !== "." &&
            userInput.value.includes(".")
        ) {
            userInput.value += button.innerHTML //additonal 2 digits 0-9
        }
    })
})

I haven’t got tot the sale button yet but really don’t know how to clear that one of regex. Why does regex cause these problems?

Because your regex was incorrect and unnecessary. Here’s a simpler example for the input event handler without regex. It can be further improved, but let’s aim for simplicity in the statements. Keep it simple! :grin:

const userInput = document.getElementById("cash");
const numbers = [...document.querySelectorAll("#numbers > .button")]

numbers.forEach((button) => {
  const input = button.innerHTML;
    button.addEventListener("click", () => {
      numberClickHandler(input);
    })
})

const numberClickHandler = (input) => {
  if (input === "." && userInput.value.includes(".")) {
    return;
  }
  if (!userInput.value.includes(".")) {
    if (userInput.value.length < 3 && input !== ".") {
      userInput.value += input;
    } else if (input === ".") {
      if (userInput.value.length === 0) {
        return;
      }
      userInput.value += ".";
    }
  } else {
    const parts = userInput.value.split(".");
    if (parts[1].length < 2) {
      userInput.value += input;
    }
  }
}

And then lets show it right format:

const frwdBtn = document.getElementById("frwdBtn");
const saleInputs = document.querySelector("#inputs > ul");
function addSaleValue() {
    const value = userInput.value.includes('.')?userInput.value: `${userInput.value}.00`; //what if there is only one number after dot, I believe you can handle this too..
    const saleValue = document.createElement("li");
    saleValue.appendChild(document.createTextNode(`$${value}`));
    saleInputs.appendChild(saleValue);
    userInput.value = "";
}
frwdBtn.onclick = () => {
    if(!drawerOpen) {
        addSaleValue();
    }
}

After that, related calculations can be made using userInput.value as a number. If you need to sum all list elements, you can store the list elements’ values before formatting them with a dollar sign and ‘.’. Additionally, dollarRegex is not necessary and is not completely correct.
I hope this will helps you
Happy coding!

By the way if you want to see right regex version, here is the example of it. The problem is regex going longer and complicated but code is very clean and simple…

const numberClickHandler = (input) => {
  const regex = /^(?:\d{0,3}(?:\.\d{0,2})?)?$/;
    const newValue = userInput.value + input;
    if (newValue.match(regex)) {
      userInput.value = newValue;
    }
}

There’s never just one solution, but there’s always a better one. :sweat_smile:

Thank you so much for the help. Take a look at what I’ve done.

Firstly, I did pretty much copy yours across. I can understand what you’ve written and don’t really see the point in changing it or rewriting it.
However, I did add a couple bits such as ‘cannot start with “00”’ and ‘only 1 “0” allowed’.

//keypad add number
const userInput = document.getElementById("cash");
const numbers = [...document.querySelectorAll("#numbers > .button")]

numbers.forEach((button) => {
    const input = button.innerHTML;
    button.addEventListener("click", () => {
        numberClickHandler(input);
    })
})

const numberClickHandler = (input) => {
    if(input === "00" && userInput.value === "") { // cannot start with "00"
        return;
    }
    if (input === "." && userInput.value.includes(".")) { // only 1 "." allowed
        return;
    }
    if (!userInput.value.includes(".")) {
        if (userInput.value.length < 3 && input !== ".") { // up to 3 digits
            if(userInput.value.slice(0) === "0") { // only 1 "0" allowed
                return;
            } else {
                userInput.value += input;
            }
        } else if (input === ".") {
            if (userInput.value.length === 0) { // cannot start with "."
                return;
            }
            userInput.value += ".";
        }
    } else {
        const parts = userInput.value.split("."); // up to 2 digits after decimal
        if (parts[1].length < 2) {
            userInput.value += input;
        }
    }
}

Secondly, I did pretty much the same with your forward button solution. But I did change the ternary for a triple if statement to include as you described “what if only one number after dot”.

//Forward Button
const frwdBtn = document.getElementById("frwdBtn");
const saleInputs = document.querySelector("#inputs > ul");
function addSaleValue() {
    const value = (input) => {
        if(input.value.includes(".")) {
            const parts = userInput.value.split(".");
            if (parts[1].length < 2 && parts[1].length >= 1) { // if only 1 digit after decimal
                return `${userInput.value}0`;
            } else if(userInput.value.slice(-1) === ".") { // if no digits after decimal
                return `${userInput.value}00`
            } else {
                return userInput.value;
            }
        } else { // if no decimal
            return `${userInput.value}.00`;
        }
    }
    const saleValue = document.createElement("li");
    saleValue.appendChild(document.createTextNode(`$${value(userInput)}`));
    saleInputs.appendChild(saleValue);
    userInput.value = "";
}
frwdBtn.onclick = () => {
    if(!drawerOpen) {
        addSaleValue();
    }
}

@0x74h51N works like a well oiled machine now :grinning:

1 Like

Great! I looked at your code, and it’s great. You’ve learned a tactic and used it; handling just one zero input is quite clever. :ok_hand::grin:

Keep going! If you face a new issue, feel free to ask, but it would be better if it’s on a new and specific issue.
Hapy coding!