PrimeSteak

Expert Member
Joined
Nov 7, 2020
Messages
1,587
Hey guys, can someone give a quick look at my code for a calculator that takes a user's age in years and converts it into seconds. While I think my code is sound, Windows says otherwise....

1627721440103.png

But I ran my code through an online js code validator and it gave me the all clear? So what else should I do to get it running?

Code is in this repo (the age_in_secs.js file):
 

ScorpioZA

Member
Joined
Jan 23, 2018
Messages
13
Hey guys, can someone give a quick look at my code for a calculator that takes a user's age in years and converts it into seconds. While I think my code is sound, Windows says otherwise....

View attachment 1117720

But I ran my code through an online js code validator and it gave me the all clear? So what else should I do to get it running?

Code is in this repo (the age_in_secs.js file):


Try running the JS in a browser rather. Your code seems valid, but running it via Microsoft script host is not ideal (clicking on js file directly).

Microsoft script host specifically does not support Javascript 'let'. Let was only introduced in ES6. You wil see in the error dialog that it has a problem on Line 6, which is where your let is.

Hope that helps.
 

_kabal_

Expert Member
Joined
Oct 24, 2005
Messages
3,805
Whatever you are using to run that doesn’t understand ES6
Change to “var months = age * 12;”
 

PrimeSteak

Expert Member
Joined
Nov 7, 2020
Messages
1,587
Microsoft script host specifically does not support Javascript 'let'. Let was only introduced in ES6. You wil see in the error dialog that it has a problem on Line 6, which is where your let is.

Hope that helps.
Ahhhh, ok. That makes sense
 

PrimeSteak

Expert Member
Joined
Nov 7, 2020
Messages
1,587
I just went through my code, it's this one damn line that's causing my main suffering (I'm running the js through https://onecompiler.com)

This one:
age = parseInt( prompt("What is your age in years: ") );

If I change the age to any other number, then the calculator works. But otherwise, that line causes the try..catch to go off and it gives me a NaN answer

Is there any other way of getting input through the command line? Sort of like input() in Python..?
 

_kabal_

Expert Member
Joined
Oct 24, 2005
Messages
3,805
Use a form input? At least you can then validate it in a nicer way
 

Johnatan56

Honorary Master
Joined
Aug 23, 2013
Messages
29,739
I just went through my code, it's this one damn line that's causing my main suffering (I'm running the js through https://onecompiler.com)

This one:
age = parseInt( prompt("What is your age in years: ") );

If I change the age to any other number, then the calculator works. But otherwise, that line causes the try..catch to go off and it gives me a NaN answer

Is there any other way of getting input through the command line? Sort of like input() in Python..?
You can't use prompt there.

Rather save this to a .html file, run that file.
JavaScript:
<!DOCTYPE html>
<html>
<body>
    <script>
        // calculate the user's age in seconds
        function calculate_age(age_year) {
            // get the months from the years
            var months, days, hours, minutes;
            months = age_year * 12;
            // 30 days were used as a common denominator for each month
            days = months * 30;
      
            //get the hours from the days
            hours = days * 24;
            //get the minutes from the hours
            minutes = hours * 60;
            //get the seconds from the hours
            var seconds = minutes * 60;
            return seconds;
        };
        // get the user's age in years
        function get_age() {
            var age;
            try {
                age = parseInt( prompt("What is your age in years: ") );
            } catch (TypeError) {
                console.log("Invalid input entered");
            }
            return age;
        };
        // output the user's age in seconds
        console.log("Age in seconds: " + calculate_age(get_age()));
    </script>
</body>
</html>

1627745174082.png
Entering 20:
1627745190718.png

I'd have made it an alert probably. And as said, learn to change that to a form, etc., but you're still starting out so all good.
My suggestion is to never use parseInt(prompt()); in one step, you should write code so that it does one thing at a time, it can become very difficult if you have too much happening on the same line, e.g. here you're displaying a prompt, getting a result, and converting that result to an int, move the step of conversion to a new line, you could maybe want to do extra checks etc. to make sure it's a number (if checks).

Use something like VS Code to edit so you get code highlighting:

Extension if you are interested that are good:
Emmet (built-in, hit tab on suggestions)
bracket pair colorizer 2
Prettier
Gitlens
Eslint
auto rename
auto close
material theme

In terms of your code, next steps:
- make it into a form with a submit button
- handle bad input (e.g. text (syntax since parseInt), negative numbers(semantic), unrealistic numbers like 3000 (semantic))
- change to calculate by year then day, calculate leap years
- change after to using date (you should use built-in, then date-fns and understand what the difference is/why you'd want date-fns)

Once you run directly in browser, you can use let, const and var.
Var = global variable if defined outside of a function, if declared within a function block, it's available in the entire function.
Let = only within the scope it is declared, if e.g. in for loop, it will only exist within that loop, by scope I mean {}.
Const = constant, you're not assigning a different value after declaration, only exists withing scope.
Good read: https://www.freecodecamp.org/news/var-let-and-const-whats-the-difference/
 
Last edited:

PrimeSteak

Expert Member
Joined
Nov 7, 2020
Messages
1,587
View attachment 1117922
Entering 20:
View attachment 1117924

I'd have made it an alert probably. And as said, learn to change that to a form, etc., but you're still starting out so all good.
Ok, will do. I'll make the HTML and add a form to it, then push it to GitHub and give an update if things are working or not...
My suggestion is to never use parseInt(prompt()); in one step, you should write code so that it does one thing at a time, it can become very difficult if you have too much happening on the same line, e.g. here you're displaying a prompt, getting a result, and converting that result to an int, move the step of conversion to a new line, you could maybe want to do extra checks etc. to make sure it's a number (if checks).
That's my belief too, to break up the steps into multiple pieces instead of jamming everything into one line, yet the internet teaches otherwise...
Use something like VS Code to edit so you get code highlighting:

Extension if you are interested that are good:
Emmet (built-in, hit tab on suggestions)
bracket pair colorizer 2
Prettier
Gitlens
Eslint
auto rename
auto close
material theme
The funny thing is I did use VS Code, lol
 

PrimeSteak

Expert Member
Joined
Nov 7, 2020
Messages
1,587

Johnatan56

Honorary Master
Joined
Aug 23, 2013
Messages
29,739

Ok, so @Johnatan56 I made the changes as you said, but I have one problem. I don't get any output....
Not sure what I can do, the new JS code I made is valid (ran it through a validator again). So idk...
Line 48 already triggers before the body is loaded, the JS thread reading it crashes when an error is encountered and does not continue executing the script (including listeners, etc.)
If you need to access the body, you can't have the script execute before the html is rendered, so move the script to the end of the body.

Check your console for errors (hit F12) and go to the console tab.

Your empty action is going to send to a new page.

JavaScript:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Age in seconds</title>
    <style>
        h1, p, form {
            display: flex;
            flex: 1.5 1 auto;
            padding: 0.5em;
        }
        body {
            font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
            text-align: center;
            border-radius: 0.75em;
            border: 1px black solid;
            margin: auto 2em auto 2em;
        }
        p {
            font-size: 1.5em;
        }
        input {
            margin: auto 0.5em auto 0.5em;
        }
        button {
            display: block;
            padding: 0.3em;
        }
    </style>
</head>
<body>
    <h1>Age in seconds calculator</h1>
    <p>Convert your age into seconds!</p>
    <form id="ageCalcForm">
        <label for="age">Enter your age in years:</label>
        <input type="number" min='1' max='120' name='age' id='age'>
        <button type="submit" id='sub'>Calculate</button>
    </form>
    <p id='output'></p>
     <script>
     
        const ageCalcForm = document.getElementById('ageCalcForm');
        const output = document.getElementById("output");
        ageCalcForm.addEventListener('submit', (event) => {
            //stop the form from submitting so it doesn't go to a new page:
            event.preventDefault();
            const age = calculate_age(get_age());
            //output.innerHTML = "Age in seconds: " + age + " seconds"
            //More correct as get_age should fetch age, get_age should only do that,
            // it should not do more than it says, which is fetching it.
            if (age < 0) {
                output.innerHtml = 'Age must be greater than 1.';
            } else {
                output.innerHTML = `Age in seconds: ${age} seconds`;
            }
            //Cleaner as clear that innerHTML is always set:
            output.innerHTML = age < 0
                ? 'Age must be greater than 1.'
                : `Age in seconds: ${age} seconds`;
        })
        // calculate the user's age in seconds
        function calculate_age(age_year) {
            // get the months from the years
            var months, days, hours, minutes;
            months = age_year * 12;
            // 30 days were used as a common denominator for each month
            days = months * 30;
       
            //get the hours from the days
            hours = days * 24;
            //get the minutes from the hours
            minutes = hours * 60;
            //get the seconds from the minutes
            var seconds = minutes * 60;
            return seconds;
        };
        // get the user's age in years
        function get_age() {
            var ageElement = document.getElementById("age");
            try {
                return parseInt(ageElement.value);
            } catch (TypeError) {
                output.innerHTML = "Invalid input entered";
                return -1;
            }
        };
   
    </script>
</body>
</html>

Things to look out for:
- age of 0, technically valid, so the min needs to be fixed.
- don't deal with all clicks, you're only handling submission of the form, you don't care if they got it via e.g. clicking the submit button, hitting the enter key, etc., be as generic as possible while being specific enough to get the job done, if we want a special action for click, form submission should not override it.

I added string interpolation (javascript calls them template strings because it's special) and ternary operators.

Things to do:
- fix 0 age
- external stylesheet
- let/const in some places
- understand that get_age should be allowed to throw an error and you should only catch it as late as possible, in the submissions, since -1 is now a magic number but what you rather wanted was that it says error with the number (must be a positive integer).
- get age shouldn't access html

Another thing to learn:
Comments should not say what the function does, you can read the name and see, comments should only be there to explain business logic or be a quick summary if making it as a doc, if you need a comment for a function to explain what it does, it's probably doing too much.
You can comment for functions for e.g. external stuff, not if internal and only used on that page.
The issue is the comment also needs to be maintained, it should be worth the effort.
 

PrimeSteak

Expert Member
Joined
Nov 7, 2020
Messages
1,587
JavaScript:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Age in seconds</title>
    <style>
        h1, p, form {
            display: flex;
            flex: 1.5 1 auto;
            padding: 0.5em;
        }
        body {
            font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
            text-align: center;
            border-radius: 0.75em;
            border: 1px black solid;
            margin: auto 2em auto 2em;
        }
        p {
            font-size: 1.5em;
        }
        input {
            margin: auto 0.5em auto 0.5em;
        }
        button {
            display: block;
            padding: 0.3em;
        }
    </style>
</head>
<body>
    <h1>Age in seconds calculator</h1>
    <p>Convert your age into seconds!</p>
    <form id="ageCalcForm">
        <label for="age">Enter your age in years:</label>
        <input type="number" min='1' max='120' name='age' id='age'>
        <button type="submit" id='sub'>Calculate</button>
    </form>
    <p id='output'></p>
     <script>
    
        const ageCalcForm = document.getElementById('ageCalcForm');
        const output = document.getElementById("output");
        ageCalcForm.addEventListener('submit', (event) => {
            //stop the form from submitting so it doesn't go to a new page:
            event.preventDefault();
            const age = calculate_age(get_age());
            //output.innerHTML = "Age in seconds: " + age + " seconds"
            //More correct as get_age should fetch age, get_age should only do that,
            // it should not do more than it says, which is fetching it.
            if (age < 0) {
                output.innerHtml = 'Age must be greater than 1.';
            } else {
                output.innerHTML = `Age in seconds: ${age} seconds`;
            }
            //Cleaner as clear that innerHTML is always set:
            output.innerHTML = age < 0
                ? 'Age must be greater than 1.'
                : `Age in seconds: ${age} seconds`;
        })
        // calculate the user's age in seconds
        function calculate_age(age_year) {
            // get the months from the years
            var months, days, hours, minutes;
            months = age_year * 12;
            // 30 days were used as a common denominator for each month
            days = months * 30;
      
            //get the hours from the days
            hours = days * 24;
            //get the minutes from the hours
            minutes = hours * 60;
            //get the seconds from the minutes
            var seconds = minutes * 60;
            return seconds;
        };
        // get the user's age in years
        function get_age() {
            var ageElement = document.getElementById("age");
            try {
                return parseInt(ageElement.value);
            } catch (TypeError) {
                output.innerHTML = "Invalid input entered";
                return -1;
            }
        };
  
    </script>
</body>
</html>
Ok, I think I get it now, I struggle a bit with JS when it comes to getting values from HTML elements and manipulating them (In other words I struggle with JS DOM) but I get it a bit more now. Also, I didn't think of making the form and output values constants, lol. Oh well, live and learn I guess...
I added string interpolation (javascript calls them template strings because it's special)
Ahhh, so you used the JS equivalent of f"{value}" in Python. Cool
Another thing to learn:
Comments should not say what the function does, you can read the name and see, comments should only be there to explain business logic or be a quick summary if making it as a doc, if you need a comment for a function to explain what it does, it's probably doing too much.
So what should I say in a comment then? Cause I thought you are supposed to use comments to explain the thought process and working of the app/program/whatever. Like describing the function of the functions or why you recursed instead of using loops like a normal person, etc?
 

Johnatan56

Honorary Master
Joined
Aug 23, 2013
Messages
29,739
Ok, I think I get it now, I struggle a bit with JS when it comes to getting values from HTML elements and manipulating them (In other words I struggle with JS DOM) but I get it a bit more now. Also, I didn't think of making the form and output values constants, lol. Oh well, live and learn I guess...
Yeah, you're not reassign it as something else, it stays as the DOM element, even if that DOM element's attributes change.
Ahhh, so you used the JS equivalent of f"{value}" in Python. Cool

So what should I say in a comment then? Cause I thought you are supposed to use comments to explain the thought process and working of the app/program/whatever. Like describing the function of the functions or why you recursed instead of using loops like a normal person, etc?
You explain the thought process, sure, but your code itself is an explanation of that thought process, why write a comment when the code/name says what it does?
You write things like business rules as comments, e.g. you hardcode a value, why is that value chosen, comment of -1 on the get age meaning that it didn't succeed as age cannot be negative, etc.

You saying why you made a recursive vs a loop doesn't matter, your code should be able to say why. As an aside, I would throw out your code if you used recursion where a loop would do the same thing, a loop is generally quite a bit faster, each time you use recursion you make a function call added to the stack and if lots of repeats, you'll probably do something and blow the stack (stack overflow), we use recursion to make the problem "simpler" as functional programming is usually better at following the way we speak (and therefore often think). So for recursion there will often enough be a comment explaining the business reason of why that approach was taken.
 

GreGorGy

BULLSFAN
Joined
Jan 18, 2005
Messages
15,280
That challenge is to calculate age in seconds and it does not seem to care that it should come from a date. So, with that in mind, the solution is much shorter if you use date methods. Does this challenge specify anything like that?

My solution would be
Code:
function AgeToSeconds(y)
    {
    var Nowish = new Date() , Thenish = new Date();
    Thenish.setFullYear(Nowish.getDate() - parseInt(y));
    return (Nowish.getTime() - Thenish.getTime())/1000;
    }
 
Last edited:
Top