{"id":20178763,"url":"https://github.com/chanda-abdul/angular-multi-step-form","last_synced_at":"2025-09-21T17:31:42.525Z","repository":{"id":108539225,"uuid":"589382971","full_name":"Chanda-Abdul/Angular-Multi-step-form","owner":"Chanda-Abdul","description":"This is a solution to the Multi-Step Form Challenge on Frontend Mentor using Angular.","archived":false,"fork":false,"pushed_at":"2023-03-16T02:04:27.000Z","size":1687,"stargazers_count":9,"open_issues_count":0,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-04T06:24:02.781Z","etag":null,"topics":["angular","frontend-mentor","material-ui","multi-step-form","reactive-forms","rxjs","scss"],"latest_commit_sha":null,"homepage":"https://dazzling-crisp-559db7.netlify.app/","language":"SCSS","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/Chanda-Abdul.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-01-16T00:56:34.000Z","updated_at":"2025-03-04T11:26:45.000Z","dependencies_parsed_at":null,"dependency_job_id":"32ec6622-281f-4b25-8633-b08b5e94a6cc","html_url":"https://github.com/Chanda-Abdul/Angular-Multi-step-form","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Chanda-Abdul/Angular-Multi-step-form","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Chanda-Abdul%2FAngular-Multi-step-form","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Chanda-Abdul%2FAngular-Multi-step-form/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Chanda-Abdul%2FAngular-Multi-step-form/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Chanda-Abdul%2FAngular-Multi-step-form/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Chanda-Abdul","download_url":"https://codeload.github.com/Chanda-Abdul/Angular-Multi-step-form/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Chanda-Abdul%2FAngular-Multi-step-form/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276274603,"owners_count":25614457,"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","status":"online","status_checked_at":"2025-09-21T02:00:07.055Z","response_time":72,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","frontend-mentor","material-ui","multi-step-form","reactive-forms","rxjs","scss"],"created_at":"2024-11-14T02:23:20.783Z","updated_at":"2025-09-21T17:31:42.152Z","avatar_url":"https://github.com/Chanda-Abdul.png","language":"SCSS","readme":"# Frontend Mentor - Multi-step Form solution\n![Design preview for the Multi-step form coding challenge](/src/assets/design/desktop-preview.jpg)\n\nThis is a solution to the [Multi-step form challenge on Frontend Mentor](https://www.frontendmentor.io/challenges/multistep-form-YVAnSdqQBJ). Frontend Mentor challenges help you improve your coding skills by building realistic projects. \n# Frontend Mentor - Multi-step form\n\n\n\n## Table of contents\n\n- [Overview](#overview)\n  - [The challenge](#the-challenge)\n  - [Screenshots](#screenshots)\n  - [Links](#links)\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- [Author](#author)\n\n## Overview\n\n### The challenge\n\nUsers should be able to:\n\n- [x] Complete each step of the sequence\n- [x] See a summary of their selections on the final step and confirm their order\n- [x] View the optimal layout for the interface depending on their device's screen size\n- [x] See hover and focus states for all interactive elements on the page\n## Links\n\n\n\u003cb\u003eSolution URL:\u003c/b\u003e [here](https://github.com/Chanda-Abdul/Angular-Multi-step-form) | \u003cb\u003eLive Site URL:\u003c/b\u003e [here](https://dazzling-crisp-559db7.netlify.app/)\n\n\n\n\n## Built with\n\u003cimg src=\"https://img.shields.io/badge/Angular-DD0031?style=for-the-badge\u0026logo=angular\u0026logoColor=white\" alt=\"Angular icon\" height=\"30\" /\u003e \u003cimg src=\"https://img.shields.io/badge/Material--UI-0081CB?style=for-the-badge\u0026logo=material-ui\u0026logoColor=white\" alt=\"Material UI icon\" height=\"30\" /\u003e \u003cimg src=\"https://img.shields.io/badge/Sass-CC6699?style=for-the-badge\u0026logo=sass\u0026logoColor=white\" alt=\"Sass icon\" height=\"30\" /\u003e \u003cimg src=\"https://img.shields.io/badge/CSS3-1572B6?style=for-the-badge\u0026logo=css3\u0026logoColor=white\" alt=\"CSS icon\" height=\"30\" /\u003e \u003cimg src=\"https://img.shields.io/badge/TypeScript-007ACC?style=for-the-badge\u0026logo=typescript\u0026logoColor=white\" alt=\"TypeScript icon\" height=\"30\" /\u003e \u003cimg src=\"https://img.shields.io/badge/JavaScript-323330?style=for-the-badge\u0026logo=javascript\u0026logoColor=F7DF1E\" alt=\"JavaScript icon\" height=\"30\" /\u003e \u003cimg src=\"https://img.shields.io/badge/HTML5-E34F26?style=for-the-badge\u0026logo=html5\u0026logoColor=white\" alt=\"HTML icon\" height=\"30\" /\u003e \u003cimg src=\"https://img.shields.io/badge/Netlify-00C7B7?style=for-the-badge\u0026logo=netlify\u0026logoColor=white\" alt=\"Netlify icon\" height=\"30\" /\u003e \u003cimg src=\"https://img.shields.io/badge/Figma-F24E1E?style=for-the-badge\u0026logo=figma\u0026logoColor=white\" alt=\"Figma icon\" height=\"30\" /\u003e\n\n## Screenshots\n\u003c!-- \u003cdetails\u003e\n\u003csummary\u003e --\u003e\n\u003cb\u003e Mobile Screenshots @ 375px\u003c/b\u003e\n\u003c!-- \u003c/summary\u003e --\u003e\n\n### Step 1\n\u003cimg src=\"src/assets/screens/mobile-step-1.png\" width=\"375px\"/\u003e\n\n#### Error Validation\n\u003cimg src=\"src/assets/screens/mobile-step-1-error.png\" width=\"375px\"/\u003e\n\n### Step 2\n\u003cimg src=\"src/assets/screens/mobile-step-2.png\" width=\"375px\"/\u003e\n\n### Step 3\n\u003cimg src=\"src/assets/screens/mobile-step-3.png\" width=\"375px\"/\u003e\n\n### Step 4\n\u003cimg src=\"src/assets/screens/mobile-step-4.png\" width=\"375px\"/\u003e\n\n### Confirmation\n\u003cimg src=\"src/assets/screens/mobile-step-5.png\" width=\"375px\"/\u003e\n\n\u003c!-- \u003c/details\u003e --\u003e\n\n\u003c!-- \u003cdetails\u003e\n\u003csummary\u003e --\u003e\n\u003cb\u003e Desktop Screenshots @ 1440px\u003c/b\u003e\n\u003c!-- \u003c/summary\u003e --\u003e\n\n### Step 1\n\u003cimg src=\"src/assets/screens/desktop-step-1.png\"/\u003e\n\n#### Error Validation\n\u003cimg src=\"src/assets/screens/desktop-step-1-error.png\"/\u003e\n\n### Step 2\n\u003cimg src=\"src/assets/screens/desktop-step-2.png\"/\u003e\n\n### Step 3\n\u003cimg src=\"src/assets/screens/desktop-step-3.png\"/\u003e\n\n### Step 4\n\u003cimg src=\"src/assets/screens/desktop-step-4.png\"/\u003e\n\n### Confirmation\n\u003cimg src=\"src/assets/screens/desktop-step-5.png\"/\u003e\n\n\u003c!-- \u003c/details\u003e --\u003e\n\n\n\n## My process\n### Setup\nInitially found it challenging to figure out how to decide how to arrange the form and where state should live. I started with everything inside one form component, but as the component grew it became difficult to keep track of everything, So I ultimately decided to have a \u003ci\u003e`\u003cForm\u003e`([code]() | [live]())\u003c/i\u003e component with all of the nested childeren for each step. Each step has a decent amount of functionaly and styling so I decided this was the best approach.\n- `\u003cstep-two-plan-details\u003e`([code]() | [live]())\n  - `\u003cstep-one-plan-details\u003e`([code]() | [live]())\n  - `\u003cstep-two-plan-details\u003e`([code]() | [live]())\n  - `\u003cstep-three-add-ons.component\u003e`([code]() | [live]())\n  - `\u003cstep-four-plan-details\u003e`([code]() | [live]())\n  - `\u003cstep-five-plan-details\u003e`([code]() | [live]())\n\n### State Management\n- I knew that I would like to have seperate components for the \u003ci\u003e`\u003cstep-tracker-icons\u003e`([code]() | [live]())\u003c/i\u003e, and the \u003ci\u003e`\u003cprogression-buttons\u003e`([code]() | [live]())\u003c/i\u003e and the \u003ci\u003e`\u003cform\u003e`([code]() | [live]())\u003c/i\u003e. Initally I used `@Input()`'s and `@Output()`'s within the form to update the `activeStep` and `stepForm`. \n- I knew that I would later move `activeStep` and `stepForm` to a service, for better readability, maintainabilty, and scalability.\n- In `FormService` the `activeStep`piece of state can be viewed and updated with an \u003cb\u003eObservable\u003c/b\u003e.  \n```ts\n...\n\nprivate activeStepSubject = new BehaviorSubject\u003cnumber\u003e(1); \n\nactiveStep$ = this.activeStepSubject.as\u003cb\u003eObservable\u003c/b\u003e();\n\n...\n\ngoToNextStep(number: number) {\n    this.activeStepSubject.next(number + 1);\n}\n```\n- Components can then access `activeStep$ ` by subscribing to the \u003cb\u003eObservable\u003c/b\u003e\n```ts\n  this.formService.activeStep$.subscribe(\n      step =\u003e this.activeStep$ = step\n    );\n```\n- The reactive `stepForm` also lives within the `FormService` so that it can be viewed and updated by multiple components as necessary\n```ts\n  multiStepForm: FormGroup = this.fb.group({\n    personalDetails: this.fb.group({\n      name: ['', [Validators.required, Validators.minLength(4)]],\n      email: ['', [Validators.required, Validators.email]],\n      phone: ['', [Validators.required, Validators.minLength(10)]],\n\n    }),\n    planDetails: this.fb.group({\n      plan: ['arcade', [Validators.required]],\n      duration: ['monthly', [Validators.required]],\n      planCost: [9],\n      totalCost: [9]\n    }),\n    addOnDetails: this.fb.group({\n      service: [false],\n      serviceCost: [0],\n      storage: [false],\n      storageCost: [0],\n      customization: [false],\n      customizationCost: [0],\n    })\n  })\n```\n\n\n### What I learned\n- `FormGroupDirective`\n- How to work with Material UI components\n\n- How to use a Service to manage data that can be shared between multiple components\n\n\n### Continued development\n- Things get a bit wonky around the tablet breakpoint of 768px, so I would like to add a few tablet styles. \n- There's not much I would add to this, but this multi-step form would serve as a great tempalte for future projects.\n\n\n\n### Useful resources\n- [\u003cimg src=\"https://img.shields.io/badge/YouTube-FF0000?style=for-the-badge\u0026logo=youtube\u0026logoColor=white\" alt=\"Youtube icon\" /\u003e Split an Angular Reactive Form model into child components ](https://youtu.be/2DOkiQFB5ic) - This helped me for XYZ reason. I really liked this pattern and will use it going forward.\n- [\u003cimg src=\"https://img.shields.io/badge/Material--UI-0081CB?style=for-the-badge\u0026logo=material-ui\u0026logoColor=white\" alt=\"Material UI icon\" height=\"30\" /\u003e Material Button toggle](https://material.angular.io/components/button-toggle/overview) - This helped me for XYZ reason. I really liked this pattern and will use it going forward. `\u003cmat-button-toggle\u003e` are on/off toggles with the appearance of a button. \n- [\u003cimg src=\"https://img.shields.io/badge/Material--UI-0081CB?style=for-the-badge\u0026logo=material-ui\u0026logoColor=white\" alt=\"Material UI icon\" height=\"30\" /\u003e Material Checkbox](https://material.angular.io/components/checkbox/overview) - This is an amazing article which helped me finally understand XYZ. I'd recommend it to anyone still learning this concept.`\u003cmat-checkbox\u003e` provides the same functionality as a native `\u003cinput type=\"checkbox\"\u003e` enhanced with Material Design styling and animations.\n\n- [\u003cimg src=\"https://img.shields.io/badge/Material--UI-0081CB?style=for-the-badge\u0026logo=material-ui\u0026logoColor=white\" alt=\"Material UI icon\" height=\"30\" /\u003e Creating a Custom @NgModule for Material Components in Angular](https://armno.medium.com/creating-a-custom-material-module-in-angular-ee6a5e925d30) - To keep AppModule clean, we can create another NgModule that takes care of importing Material modules to use. \n\u003c!-- - [Example resource 1](https://www.example.com) - This helped me for XYZ reason. I really liked this pattern and will use it going forward.\n- [Example resource 2](https://www.example.com) - This is an amazing article which helped me finally understand XYZ. I'd recommend it to anyone still learning this concept. --\u003e\n\n## Author\n\n- Frontend Mentor - [@Chanda-Abdul](https://www.frontendmentor.io/profile/Chanda-Abdul)\n- Website - [Chanda Codes](https://chandacodes.com/)\n- GitHub - [github.com/Chanda-Abdul](https://github.com/Chanda-Abdul)\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchanda-abdul%2Fangular-multi-step-form","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchanda-abdul%2Fangular-multi-step-form","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchanda-abdul%2Fangular-multi-step-form/lists"}