{"id":21307358,"url":"https://github.com/jdegand/age-calculator-app","last_synced_at":"2026-05-20T03:33:28.028Z","repository":{"id":176157910,"uuid":"627641823","full_name":"jdegand/age-calculator-app","owner":"jdegand","description":"Frontend Mentor Challenge - Age Calculator App","archived":false,"fork":false,"pushed_at":"2024-07-25T02:47:11.000Z","size":921,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-22T09:12:38.994Z","etag":null,"topics":["angular","angular15","date-fns","frontend-mentor"],"latest_commit_sha":null,"homepage":"https://jdegand.github.io/age-calculator-app/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jdegand.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-04-13T22:30:00.000Z","updated_at":"2024-07-25T19:20:35.000Z","dependencies_parsed_at":null,"dependency_job_id":"237cc217-a5c7-471c-9ac6-8074d2b218a6","html_url":"https://github.com/jdegand/age-calculator-app","commit_stats":null,"previous_names":["jdegand/age-calculator-app"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdegand%2Fage-calculator-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdegand%2Fage-calculator-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdegand%2Fage-calculator-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdegand%2Fage-calculator-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jdegand","download_url":"https://codeload.github.com/jdegand/age-calculator-app/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243784103,"owners_count":20347409,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","angular15","date-fns","frontend-mentor"],"created_at":"2024-11-21T16:31:32.155Z","updated_at":"2026-05-20T03:33:22.998Z","avatar_url":"https://github.com/jdegand.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Frontend Mentor - Age calculator app solution\n\nThis is a solution to the [Age calculator app challenge on Frontend Mentor](https://www.frontendmentor.io/challenges/age-calculator-app-dF9DFFpj-Q). Frontend Mentor challenges help you improve your coding skills by building realistic projects. \n\n## Table of contents\n\n- [Overview](#overview)\n  - [The challenge](#the-challenge)\n  - [Link](#link)\n  - [Screenshots](#screenshots)\n- [My process](#my-process)\n  - [Built with](#built-with)\n  - [What I learned](#what-i-learned)\n  - [Continued development](#continued-development)\n  - [Useful resources](#useful-resources)\n\n## Overview\n\n### The challenge\n\nUsers should be able to:\n\n- View an age in years, months, and days after submitting a valid date through the form\n- Receive validation errors if:\n  - Any field is empty when the form is submitted\n  - The day number is not between 1-31\n  - The month number is not between 1-12\n  - The year is in the future\n  - The date is invalid e.g. 31/04/1991 (there are 30 days in April)\n- View the optimal layout for the interface depending on their device's screen size\n- See hover and focus states for all interactive elements on the page\n- **Bonus**: See the age numbers animate to their final number when the form is submitted\n\n### Link\n\n[Github Pages](https://jdegand.github.io/age-calculator-app/)\n\n### Screenshots \n\n![](screenshots/age-calculator-app-desktop-1.png)\n\n***\n\n![](screenshots/age-calculator-app-required.png)\n\n***\n\n![](screenshots/age-calculator-valid-day.png)\n\n***\n\n![](screenshots/age-calculator-multiple-errors.png)\n\n***\n\n![](screenshots/age-calculator-leap-year-error.png \"Leap year error\")\n\n***\n\n![](screenshots/age-calculator-leap-year-valid.png \"Valid leap year date error goes away\")\n\n***\n\n![](screenshots/age-calculator-leap-year-results.png \"date difference from entered date til April 13 2023\")\n\n***\n\n![](screenshots/age-calculator-mobile.png \"date difference from entered date til April 13 2023\")\n\n***\n\n## My process\n\n### Built with\n\n- Semantic HTML5 markup\n- CSS custom properties\n- Flexbox\n- CSS Grid\n- Mobile-first workflow\n- [Angular CLI](https://github.com/angular/angular-cli) version 15.2.5\n- [Angular](https://angular.io/)\n- [date-fns](https://date-fns.org/)\n\n### What I learned\n\n- Angular CLI no longer works on node 14 and on node 18 you need to workaround resolving localhost.  \n- Not the best design.  The readme description mentions submiting the form but the button / circle looks decorative and not like a submit button. \n- I originally did not have a submit button but changed to using one before I added the RealDateValidator.  \n- I added a 'Submit' tooltip to the button.  \n- No disabled color change on button in the design.  The button is not specified to be disabled at any time so you can add the validation error messages.\n- Problematic to isolate custom form validator errors and remove a specific error - I used updateValueAndValidity to get around the problem of having a lingering dateError and its associated error styling being shown after values are updated to be valid. \n- Animation works well on first submission of form (localForm.submitted value is false) - but when you change any input value to another valid number the animation runs again on the previous submission values.  \n- Used [Time And Date](https://www.timeanddate.com/) to verify calculation was working correctly.  \n- Design should have included the end date that was used when the screenshot was taken.  \n- Design is missing screenshot of error messages on mobile although error message would have to be '10px' to stay on one line.\n- Put the invalid class on the containing div to lessen code repetition - could go even further and clean up the ngIfs ?\n- When using ngIf have to worry about layout shift - better to use ngStyle or ngClass instead ?\n- Wrapped the small tags with the error messages in a fixed height div to prevent the layout shift\n- Angular testing is problematic if you use containers - you need to install a browser before you can run tests   \n- Could make some semantic html adjustments in the results section - could use dl, dd, dt tags?\n- Problem with dashes logic using localForm.submitted - after submitting form for the first time, once the form is valid again, the dashes disappear \n- tough to inspect the localForm variable - circular structure - thought I could look through its properties to fix the dash issue\n- Could have done more to shrink the design for mobile - have to lower font-size / make inputs smaller etc\n\n### Continued development\n\n- Account for 'e' in the input type=\"number\" fields\n- Remove the arrows in the input type=\"number\" fields ?\n- Testing \n- Animation\n- Mobile tweaks\n\n### Useful resources\n\n- [Github](https://github.com/angular/angular-cli/issues/24601) - angular cli and node 18 conflicts\n- [Stack Overflow](https://stackoverflow.com/questions/43492354/how-to-allow-access-outside-localhost) - allow access outside localhost\n- [Stack Overflow](https://stackoverflow.com/questions/47570251/display-reactive-form-elements-concurrently-real-time-in-angular) - display reactive form elements in real time\n- [YouTube](https://www.youtube.com/watch?v=jdsSIKgJ6ZM) - Form Validation of Reactive Forms | Reactive Form | Angular 13+\n- [Angular JS Wiki](https://www.angularjswiki.com/angular/object-is-possibly-null-error-fix/) - object is possibly null error fix\n- [PluralSight](https://www.pluralsight.com/guides/how-to-display-validation-messages-using-angular) - validation messages\n- [YouTube](https://www.youtube.com/watch?v=wOtPXAbxoM4) - Display Form Error Messages On Submit Using Angular Reactive Forms\n- [Programiz](https://www.programiz.com/javascript/examples/check-leap-year) - check leap year\n- [Stack Overflow](https://stackoverflow.com/questions/57086672/element-implicitly-has-an-any-type-because-expression-of-type-string-cant-b) - element implicitly has an any type\n- [YouTube](https://www.youtube.com/watch?v=VmdSmeDpW0k) - Custom Validation and Error Code | Reactive Forms | Angular 13+\n- [YouTube](https://www.youtube.com/watch?v=REbXP2OiGn8) - How to add custom validation with two field in Angular\n- [YouTube](https://www.youtube.com/watch?v=mK0CX-68hBE) - Angular Reactive Forms: Learn How to Create A Custom Validator\n- [Github](https://github.com/angular/angular/issues/44880) - Type '(formGroup: FormGroup) =\u003e null | undefined' is not assignable to type 'ValidatorFn'. #44880\n- [Stack Overflow](https://stackoverflow.com/questions/40349987/how-to-suppress-error-ts2533-object-is-possibly-null-or-undefined) - object is possibly null or undefined\n- [Stack Overflow](https://stackoverflow.com/questions/45069629/angular-abstract-control-remove-error) - abstract control remove error\n- [Stack Overflow](https://stackoverflow.com/questions/65966720/error-ts2531-object-is-possibly-null-in-angular-reactive-forms) - error object is possibly null\n- [W3 Schools](https://www.w3schools.com/howto/howto_css_placeholder.asp) - placeholder css\n- [Github](https://github.com/angular/angular/issues/21564) - Forms: State that setErrors() will make status === INVALID regardless of value passed for key #21564\n- [Stack Overflow](https://stackoverflow.com/questions/17732897/difference-between-two-dates-in-years-months-days-in-javascript) - difference between 2 dates in years, months, \u0026 days\n- [YouTube](https://www.youtube.com/watch?v=8BatUQYtMlY) - 5 Angular Animations Examples - Learn BrowserAnimationsModule in Angular\n- [Angular Docs](https://angular.io/guide/transition-and-triggers) - transition and triggers\n- [Github](https://github.com/angular-schule/angular-cli-ghpages) - angular cli ghpages\n- [Time and Date](https://www.timeanddate.com/) - used to verify calculation was working correctly \n- [Blog](https://blogs.halodoc.io/skip-repetition-in-angular-templates-with-custom-directives/) - custom directives\n- [Stack Overflow](https://stackoverflow.com/questions/44151171/make-angular-ng-if-reserve-space-for-showing-if-event-occurs) - make angular ngIf reserve space for showing if event occurs\n- [The Server Side](https://www.theserverside.com/blog/Coffee-Talk-Java-News-Stories-and-Opinions/gitkeep-push-empty-folders-git-commit#:~:text=What%20is%20.,to%20put%20a%20file%20named%20.) - gitkeep file\n- [Stack Overflow](https://stackoverflow.com/questions/56822743/how-to-display-an-object-object-on-angular-ui) - display an object with json pipe\n- [Stack Overflow](https://stackoverflow.com/questions/40363449/passing-form-status-data-between-parent-and-child-components) - passing form status data between parent and child components\n- [Stack Overflow](https://stackoverflow.com/questions/43759590/angular-reactive-forms-how-to-reset-form-state-and-keep-values-after-submit) - reactive forms reset form state\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjdegand%2Fage-calculator-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjdegand%2Fage-calculator-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjdegand%2Fage-calculator-app/lists"}