Build a Roman Numeral Converter Project - Build a Roman Numeral Converter

I’m running through a couple of problems in this project

When I input 0 or 4000 the error message works, but when I enter any number for example 20 I get XX and the error message with added class to the div changing it’s colors. Also when I don’t input anything and I press convert the error for that isn’t working.

<!-- file: index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href="styles.css" rel="stylesheet">
  <title>Roman Numeral Converter</title>
</head>
<body>

  <main>

    <h1 class="title">Roman Numeral Converter</h1>

    <div class="converter">
      <p class="converter-text">Enter a Number:</p>
      <input class="converter-input" id="number" required>
      <button class="converter-btn" id="convert-btn">Convert</button>
    </div>

    <div class="output" id="output"></div>
  </main>
  <script src="script.js"></script>
</body>
</html>
/* file: styles.css */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body{
  background-color: #333;
}

.title{
  text-align: center;
  padding: 3rem;
  color: white;
}

.converter{
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  align-items: center;
  border: 2px solid yellow;
  border-radius: 25px;
  width: 400px;
  height: 250px;
  margin: auto;
  background-color: #555;
  margin-bottom: 2.5rem;
}

.converter-text{
  font-size: 1.5rem;
  color: white;
  font-weight: bold;
}

.converter-input{
  width: 250px;
  height: 40px;
  background-color: #333;
  border: 1px solid yellow;
  color: white;
  font-size: 1.5rem ;
  padding: 10px;
}

.converter-btn{
  width: 250px;
  height: 40px;
  font-size: 1.2rem;
}

.output{
  width: 400px;
  height: 120px;
  border: 2px solid yellow;
  border-radius: 25px;
  margin: auto;
  color: white;
  font-size: 2.1rem;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 1rem;

}

.error{
  border: 2px solid #a94442;
  background-color: #ffadad;
  color: #850000;
}
/* file: script.js */
const inputElement = document.getElementById('number');
const buttonElement = document.getElementById('convert-btn');
const outputDiv = document.getElementById('output');


function decimalToRoman(input) {



  if(input <= 0){
    outputDiv.classList.add('error');
    return 'Please enter a number greater than or equal to 1.';
  }
  if(input >= 4000){
    outputDiv.classList.add('error');
    return 'Please enter a number less than or equal to 3999.';
  }
  
  const romanNumeralMap = [
    { value: 1000, numeral: 'M' },
    { value: 900, numeral: 'CM' },
    { value: 500, numeral: 'D' },
    { value: 400, numeral: 'CD' },
    { value: 100, numeral: 'C' },
    { value: 90, numeral: 'XC' },
    { value: 50, numeral: 'L' },
    { value: 40, numeral: 'XL' },
    { value: 10, numeral: 'X' },
    { value: 9, numeral: 'IX' },
    { value: 5, numeral: 'V' },
    { value: 4, numeral: 'IV' },
    { value: 1, numeral: 'I' }
  ];

  for (let i = 0; i < romanNumeralMap.length; i++) {
    const obj = romanNumeralMap[i];
    if (input >= obj.value) {
      return obj.numeral + decimalToRoman(input - obj.value);
    }
  }
  return '';
}

buttonElement.addEventListener('click', () =>{
  const num = inputElement.value;
  outputDiv.innerText = decimalToRoman(num);
});

inputElement.addEventListener('keydown', (e) =>{
  if(e.key === "Enter"){
    const num = inputElement.value;
    outputDiv.innerText = decimalToRoman(num);
  }
});

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36

Challenge Information:

Build a Roman Numeral Converter Project - Build a Roman Numeral Converter

Do you have any ideas how that might be happening? What have you already tried to find the cause?

I think if you log out input at the top of the function you will see the issue. Also, you are not handling the empty input case.

There is a bit of a hacky solution using typeof you can use. Log out typeof input maybe you can see what I mean.

when I console.log the input I get the number that I entered, I tried console.log typeof input and it showed me string number, as for the empty input case I added an if statement to the top checking if the input === ‘’

if(input === ''){
    outputDiv.classList.add('error');
    return 'Please enter a number.';
  }
  else if(input <= 0){
    outputDiv.classList.add('error');
    return 'Please enter a number greater than or equal to 1.';
  }
  else if(input >= 4000){
    outputDiv.classList.add('error');
    return 'Please enter a number less than or equal to 3999.';
  }
  else{
    const romanNumeralMap = [

but the error message still shows when I input any number

What I’m thinking it’s cz of the recursion, let’s say I input 50 it checks in the array for that value and returns obj.numeral + decimalToRoman(input - obj.value); so when it does the recursion it gets to a point where the input is 0 bcz we’re doing input - obj.value, but if it’s 0 error message would the 0 one, I’m getting the below zero error message.

You see it more than one time though. Does it not look to you like at some point input will be 0 and will satisfy your if statement condition?

If you really want to use recursion you will have to figure out how to deal with that issue. The typeof solution I mentioned would work as the function return type changes from the initial call.

So I should not use recursion? Could you elaborate a bit more I’m having a bit of trouble figuring out what to do. Thank you for your precious time!

A recursive approach can always be converted into an approach using a while loop. The while loop can often be easier to reason about.

Use whatever you want and works for you.

The only time input is a string is the initial user input the rest of the time when it is the return of calling the function it has been converted (coerced) to type number. As such you can use typeof to check the type and value of input and only run the conditional code if both are satisfied.

I’ll try tomorrow changing, I’ll keep you updated, thank you!

Why does it matter if the input is a string or number? How does that affect the please enter a number greater than 1 error (since that’s the one I get), I’m sorry if I’m a bit slow, but it’s a bit confusing.

The only time you need to check if the input is valid is when it also is a string.

Personally, I don’t think using a single function for this is a great idea. I would make the handler function check the input and after it is validated pass it to the recursive function which will return the final result.

I’ll try doing that, but what do you mean by “The only time you need to check if the input is valid is when it also is a string.”,

Ok I’ve updated the code now the error message won’t show if we input a number, but the the div still turns red even If I input a correct number and error message doesn’t show if the input is incorrect only the div turns red but it’s empty inside. As you see I tried using outputDiv.textContent but it still didn’t work.

function checkInput(input){
  if(input === ''){
    outputDiv.classList.add('error');
    outputDiv.textContent = 'Please enter a number between 1 and 3999.';
  }
  else if(input <= 0){
    outputDiv.classList.add('error');
    return 'Please enter a number greater than or equal to 1.';
  }
  else if(input >= 4000){
    outputDiv.classList.add('error');
    return 'Please enter a number less than or equal to 3999.';
  }
  else {
    return input;
  }
}

function decimalToRoman(input) {

  checkInput(input);
  etc...(the rest is the same)

i think you should use remove() method to toggle between them inside your event listener before you update innerText of the outputDiv

I updated my code to use remove and now when I have an error neither the colors or the text show (just an empty div) for the output div but if I input any number from 1-3999 it works.

Please post all your code.

I would suggest using the classList .toggle() method. If the element doesn’t have the class it will add it and if it does it will remove it.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href="styles.css" rel="stylesheet">
  <title>Roman Numeral Converter</title>
</head>
<body>

  <main>

    <h1 class="title">Roman Numeral Converter</h1>

    <div class="converter">
      <p class="converter-text">Enter a Number:</p>
      <input class="converter-input" id="number" required>
      <button class="converter-btn" id="convert-btn">Convert</button>
    </div>

    <div class="output" id="output"></div>
  </main>
  <script src="script.js"></script>
</body>
</html>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body{
  background-color: #333;
}

.title{
  text-align: center;
  padding: 3rem;
  color: white;
}

.converter{
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  align-items: center;
  border: 2px solid yellow;
  border-radius: 25px;
  width: 400px;
  height: 250px;
  margin: auto;
  background-color: #555;
  margin-bottom: 2.5rem;
}

.converter-text{
  font-size: 1.5rem;
  color: white;
  font-weight: bold;
}

.converter-input{
  width: 250px;
  height: 40px;
  background-color: #333;
  border: 1px solid yellow;
  color: white;
  font-size: 1.5rem ;
  padding: 10px;
}

.converter-btn{
  width: 250px;
  height: 40px;
  font-size: 1.2rem;
}

.output{
  width: 400px;
  height: 120px;
  border: 2px solid yellow;
  border-radius: 25px;
  margin: auto;
  color: white;
  font-size: 2.1rem;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 1rem;

}

.error{
  border: 2px solid #a94442;
  background-color: #ffadad;
  color: #850000;
}

.hidden {
  display: none;
}
const inputElement = document.getElementById('number');
const buttonElement = document.getElementById('convert-btn');
const outputDiv = document.getElementById('output');

function checkInput(input){
  if(input === ''){
    outputDiv.classList.toggle('error');
    outputDiv.textContent = 'Please enter a number between 1 and 3999.';
  }
  else if(input <= 0){
    outputDiv.classList.toggle('error');
    return 'Please enter a number greater than or equal to 1.';
  }
  else if(input >= 4000){
    outputDiv.classList.toggle('error');
    return 'Please enter a number less than or equal to 3999.';
  }
  else {
    return input;
  }
}

function decimalToRoman(input) {

  checkInput(input);
  outputDiv.classList.remove('error');

  const romanNumeralMap = [
    { value: 1000, numeral: 'M' },
    { value: 900, numeral: 'CM' },
    { value: 500, numeral: 'D' },
    { value: 400, numeral: 'CD' },
    { value: 100, numeral: 'C' },
    { value: 90, numeral: 'XC' },
    { value: 50, numeral: 'L' },
    { value: 40, numeral: 'XL' },
    { value: 10, numeral: 'X' },
    { value: 9, numeral: 'IX' },
    { value: 5, numeral: 'V' },
    { value: 4, numeral: 'IV' },
    { value: 1, numeral: 'I' }
  ];

  for (let i = 0; i < romanNumeralMap.length; i++) {
    const obj = romanNumeralMap[i];
    if (input >= obj.value) {
      return obj.numeral + decimalToRoman(input - obj.value);
    }
  }
  return '';
  
}

buttonElement.addEventListener('click', () =>{
  const num = inputElement.value;
  if (!num){
    outputDiv.classList.add('error');
    outputDiv.innerText = 'Please enter a valid number'
  }
  outputDiv.innerText = decimalToRoman(num);
});

inputElement.addEventListener('keydown', (e) =>{
  if(e.key === "Enter"){
    const num = inputElement.value;
    outputDiv.innerText = decimalToRoman(num);
  }
});

I know I’m using outputDiv.innerText and return in the first function (checkInput), I’m just testing rn but both didn’t work, I did try toggle for the class but it didn’t work.

Your logic/execution order for how your code runs is not correct.

  1. Put all the input validation inside checkInput and make all the statements return the required string.

  2. Make the handler call checkInput

  3. Have checkInput call decimalToRoman after its validation, passing it the value.

  4. Call classList.remove at the top of the checkInput function (always remove the class and then add it as needed, you don’t need toggle in this case but it doesn’t matter if you use add or toggle).

  1. Isn’t all the input validation inside the checkInput?
  2. What do you mean by handler?
  3. In the last else statemen is a good place to call the decimalToRoman?