This is a solution to the Age calculator app challenge on Frontend Mentor. Frontend Mentor challenges help you improve your coding skills by building realistic projects.
Your challenge is to build out an age calculator app and get it looking as close to the design as possible.
You can use any tools you like to help you complete the challenge. So if you've got something you'd like to practice, feel free to give it a go.
Your users should be able to:
- View an age in years, months, and days after submitting a valid date through the form
- Receive validation errors if:
- Any field is empty when the form is submitted
- The day number is not between 1-31
- The month number is not between 1-12
- The year is in the future
- The date is invalid e.g. 31/04/1991(there are 30 days in April)
- View the optimal layout for the interface depending on their device's screen size
- See hover and focus states for all interactive elements on the page
- Bonus: See the age numbers animate to their final number when the form is submitted
-
Becoming more comfortable using Sass with BEM styling conventions for CSS
-
JavaScript DOM Manipulation
-
JavaScript
Date()
-
Validation for user date inputs
- Validates year for current year and previous months
- Validates month input for current month and previous months
- Validates month input for current day and previous days, also checks for leap year
- also animates the ➡ button
function validateInputDate() { /* collect input from HTML form and convert into date format */ inputDate = { ... month: monthInputValue, day: dayInputValue, year: yearInputValue, }; let { month, day, year } = inputDate; /* Validate Input */ let validMonth = true; let validDay = true; let validYear = true; /* Update month for leap years */ if ((!(year % 4) && year % 100) || !(year % 400)) daysPerMonth[1] = 29; /* Validate day of month is within range*/ if (dayInputValue == null || '') { validDay = false; showError('day-input-error', 'day-error', 'This field is required'); } else if ( day > daysPerMonth[month - 1] || day > 31 || day < 1 || (day > currentDay && month == currentMonth + 1 && year == currentYear) ) { validDay = false; showError('day-input-error', 'day-error', 'Must be a valid day'); } /* Validate Month */ if (monthInputValue == null || '') { validMonth = false; showError(...); } else if ( (month > currentMonth + 1 && year == currentYear) || month < 1 || month > 12 || (day > currentDay && month == currentMonth + 1 && year == currentYear) ) { validMonth = false; showError(...); } /* Validate Year */ if (yearInputValue == null || '') { validYear = false; showError(...); } else if (year > currentYear || year < 1) { validYear = false; showError(...); } if (validMonth && validDay && validYear) { document.getElementById('btn-calculate').classList.add('slide-right'); displayOutput(); } else { document.getElementById('btn-calculate').classList.add('slide-left'); return false; } }
-
Dynamically use JavaScript to add/clear error classes to HTML elements
function showError(errorElement, errorMessageElement, errorMessage) { document.getElementById(errorElement).classList.add('input-error'); document.getElementById(errorMessageElement).classList.add('display-error'); document.getElementById(errorMessageElement).innerHTML = errorMessage; } function clearError(element) { document.getElementById('btn-calculate').classList.remove('slide-right'); document.getElementById('btn-calculate').classList.remove('slide-left'); document.getElementById(`${element}-error`).classList.remove('display-error'); document.getElementById(`${element}-input-error`).classList.remove('input-error'); }
-
Animated JavaScript Counter for output results in
displayOutput.js
function displayOutput() { let output = calculateOutput(); /* Get output elements and animate result */ animateValue(document.getElementById('year-result'), 0, output.years, 1500); ... } function animateValue(obj, start, end, duration) { let startTimestamp = null; const step = (timestamp) => { if (!startTimestamp) startTimestamp = timestamp; const progress = Math.min((timestamp - startTimestamp) / duration, 1); obj.innerHTML = Math.floor(progress * (end - start) + start); if (progress < 1) { window.requestAnimationFrame(step); } }; window.requestAnimationFrame(step); }
- Standard built-in objects
Date()
- JavaScriptDate()
objects represent a single moment in time in a platform-independent format. Date objects encapsulate an integral number that represents milliseconds since the midnight at the beginning of January 1, 1970, UTC (the epoch). - ChatGPT - to write the instructions... and some JavaScript
- Age Calculator | Javascript Project - To get some ideas
- How to display JavaScript form error message in html form - This helped.
- Animating Number Counters - How to use CSS counters to animate a number by adjusting the count.
- A Handy Little System for Animated Entrances in CSS
- Website - Chanda Abdul
- Frontend Mentor - @Chanda-Abdul
- GitHub - github.com/Chanda-Abdul