{"id":21029607,"url":"https://github.com/princev/ng-mat-form","last_synced_at":"2026-05-09T07:31:36.856Z","repository":{"id":93766257,"uuid":"144615212","full_name":"princeV/ng-mat-form","owner":"princeV","description":null,"archived":false,"fork":false,"pushed_at":"2018-08-13T18:07:30.000Z","size":129,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-01-02T21:40:31.416Z","etag":null,"topics":["angular","angular-cli","documentation","material-cli","material-ui","reactive-form"],"latest_commit_sha":null,"homepage":null,"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/princeV.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":"2018-08-13T17:57:39.000Z","updated_at":"2018-08-13T18:13:32.000Z","dependencies_parsed_at":"2023-03-04T04:30:53.135Z","dependency_job_id":null,"html_url":"https://github.com/princeV/ng-mat-form","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/princeV/ng-mat-form","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/princeV%2Fng-mat-form","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/princeV%2Fng-mat-form/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/princeV%2Fng-mat-form/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/princeV%2Fng-mat-form/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/princeV","download_url":"https://codeload.github.com/princeV/ng-mat-form/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/princeV%2Fng-mat-form/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32811269,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-08T08:22:46.396Z","status":"online","status_checked_at":"2026-05-09T02:00:06.633Z","response_time":123,"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","angular-cli","documentation","material-cli","material-ui","reactive-form"],"created_at":"2024-11-19T12:13:23.007Z","updated_at":"2026-05-09T07:31:36.840Z","avatar_url":"https://github.com/princeV.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NgMatForm\n\nThis project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 6.0.8.\n\n# Angular Material Forms example\n\nThis is a demo on how to create an angular material form using the angular and material CLI.\n\nIt includes:\n* Routing\n* Services\n* Assets (json file)\n* Reactive form control (including FormArray)\n* Form validation (including messages)\n\n## Initial Checks\n- check npm setup for production only (this was an issue I faced during setup):\n   ```bash\n   npm config get production\n   ```\n   - If it's set to true make sure to set it to false for all dev-dependencies.\n   ```bash\n   npm config set -g production false\n   ```   \n\n## Initialize project:\n- Make sure to have the latest version of node.\n- Install the angular cli (command line interface)\n```bash\n$ npm install -g @angular/cli\n```\n- Creat a new angular project.\n```bash\n$ ng new ng-mat-form --routing\n```\n\u003e --routing creates an additional app-routing.module.ts file and adds it to the\napp.module.ts imports\n- Move into your project folder.\n\n\n## Folder structure (depends on angular cli version):\n```code\n├── .git\n├── e2e\n├── node_modules\n├── src\n│   ├── app\n│   │   ├── app-routing.module.ts\n│   │   ├── app.component.css\n│   │   ├── app.component.html\n│   │   ├── app.component.spec.ts\n│   │   ├── app.component.ts\n│   │   └── app.module.ts\n│   ├── assets\n│   ├── environments\n│   │   ├── environment.prod.ts\n│   │   └── environment.ts\n│   ├── browserlist\n│   ├── favicon.ico\n│   ├── index.html\n│   ├── karma.config.js\n│   ├── main.ts\n│   ├── polyfills.ts\n│   ├── styles.css\n│   ├── test.ts\n│   ├── tsconfig.app.json\n│   ├── tsconfig.spec.json\n│   └── tslint.json\n├── angular.json\n├── package.json\n├── protractor.conf.js\n├── README.md\n└── tslint.json\n```\n\n## 1. Angular Material templates:\n### Adding to cli\n- Add the material cli options:\n```bash\n$ ng add @angular/material\n```\n   - If there are some issues with the latest version try this\n   ```bash\n   $ ng add @angular/material@6.2.1\n   ```\n\nThis will add all required imports etc. to the project and make it material \"ready\".\n\nIt will also add cli options that can be used to add templates to the project.\n\n### Navigation template:\n\nLet's add a template for the navigation of the project via material cli:\n```bash\n$ ng generate @angular/material:material-nav --name myNavigation\n```\nThis adds a new component to the project/src/app folder and makes sure that the component is setup in the app module:\n```code\n...\n│   ├── app\n│   │   ├── my-navigation\n│   │   │   ├── my-navigation.component.css\n│   │   │   ├── my-navigation.component.html\n│   │   │   ├── my-navigation.component.spec.ts\n│   │   │   ├── my-navigation.component.ts\n│   │   ├── ...\n...\n```\n#### File changes:\n__app.component.html__:  \n\ngo to and check for the selector:\n```typescript\n...\n@Component({\n  selector: 'app-my-navigation',\n  templateUrl: './my-navigation.component.html',\n  styleUrls: ['./my-navigation.component.css']\n})\n...\n```\nExchange the content of this file based on the selector, remove everything and only add the navigation component like this:\n```html\n\u003capp-my-navigation\u003e\u003c/app-my-navigation\u003e\n```\n\nCheck it out:\n```bash\n$ ng serve --open\n```\n\n## 2. Data model\nIn this example app we would like to achieve the following:\nCreate a simple user and role model as a demo for the angular reactive forms including ngFor and a FormArray.\n\nEven if it looks like, this is not about user authentication.\n\nLet's start by creating a new folder in the app (src\\app\\model) called model.\n\nNow we continue with the user model - we would like to include the following attributes:\n- id\n- username\n- password\n- email\n- roles[ {roleId, expiryDate} ]\n\nName it user.model.ts and add the following content:\n```typescript\nexport class User {\n  constructor(public id:number = 0,\n              public username:string = '',\n              public password:string = '',\n              public email:string = '',\n              public roles:Roles[] = []\n            ){}\n}\n\nclass Roles {\n    constructor(public roleId:number = 0,\n                public expiryDate:Date = new Date()\n              ){}\n}\n\n```\n\nAs of TypeScript's constructor syntax this will declare parameters and properties simultaneously and also initializes them automatically.\n\nWe will also creat a class for the roles as well (role.model.ts):\n```typescript\nexport class Role {\n  constructor(public id:number = 0,\n              public name:string = '') {\n  }\n}\n```\nWe will later link the User.roles[] to one or many Role.ids.\n\n## 3. Mockup data in assets:\n\nWe also want some mockup data.\nLet's create a file with some roles for a select on the form and for the roles[] of a user.\n\nMove to the assets folder and create a file calles role.json with the following content:\n```json\n[{\n    \"id\": 1,\n    \"name\": \"Administrator\"\n  },\n  {\n    \"id\": 2,\n    \"name\": \"Guest\"\n  },\n  {\n    \"id\": 3,\n    \"name\": \"Sales\"\n  },\n  {\n    \"id\": 4,\n    \"name\": \"Marketing\"\n  },\n  {\n    \"id\": 5,\n    \"name\": \"IT\"\n  }\n]\n```\n\n## 4. Services\nNext point to cover are the services that we would like to use.\nWe are going to create a service for the role to read all roles from the json file. This could later be changed to target a rest api or whatever.\nWe also want to make sure to place it in the service folder.\n\n```bash\n$ ng generate service service/role\n```\n\n### File changes\n\n__app.module.ts:__  \nadd the import for the HttpClient:\n```typescript\n...\nimport { HttpClientModule } from '@angular/common/http';\n...\n```\n\nand add it to the imports after the BrowserModule:\n```typescript\n...\n@NgModule({\n  ...\n  imports: [\n    BrowserModule,\n    HttpClientModule,\n    ...]\n  ...\n})\n...\n```\n__role.service.ts:__  \nChange the role service to look like this:\n\n```typescript\nimport { Injectable } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport { Role } from '../model/role.model';\nimport { Observable} from 'rxjs';\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class RoleService {\n  roleUrl = 'assets/role.json';\n\n  constructor(private http: HttpClient) { }\n\n  getRoleList(): Observable\u003cRole[]\u003e  {\n    return this.http.get\u003cRole[]\u003e(this.roleUrl);\n  }\n}\n```\n\nWe added imports for HttpClient, for the Role model, for Observable from rxjs.\n\nThen we make sure to provide it in the root via the @Injectable and we also add the HttpClient via DI in the constructor.\n\nWe also write a method to return the observable that streams a list of roles based on the role.json that we defined earlier.\n\n\n\n## 5. Routing:\n### Prerequesites:\nThe routing file should be already installed and availabe in the app folder.\n- app-routing.module.ts\n\nWe also need a component as a target for the initial page and the menu item.  \nFor that we will create the user-form component:\n```bash\n$ ng generate component user-form\n```\n\nThis will create the component file and also add them in the app module via the declaration.\n\n\n### File Changes:\n\n__app-routing.module.ts:__  \nadd the component to the router module:\n```javascript\n...\nimport{ UserFormComponent } from './user-form/user-form.component';\n...\n```\n\nand add the routes to the Routes:\n```javascript\n...\nconst routes: Routes = [\n  { path: '', redirectTo: '/user-form', pathMatch: 'full' },\n  { path: 'user-form', component: UserFormComponent }\n];\n...\n```\n\n__my-navigation.component.html:__  \nThe next things we need to do is to change the router links and add the router outlet (router hook) to the navigation content.\n\nFirst, change the navigation links to our actual target url that we setup in the routing file:\n```html\n...\n\u003cmat-nav-list\u003e\n  \u003ca mat-list-item routerLink=\"/user-form\"\u003eRegister\u003c/a\u003e\n\u003c/mat-nav-list\u003e\n...\n```\nThen move the router-outlet tag to the end of the side nav content:\n```html\n...\n   \u003cspan\u003eApplication Title\u003c/span\u003e\n  \u003c/mat-toolbar\u003e\n \u003crouter-outlet\u003e\u003c/router-outlet\u003e\n\u003c/mat-sidenav-content\u003e\n...\n```\nCheck it out:\n```bash\n$ ng serve --open\n```\nYou should see something like: user-form works! in the content area of the page.\n\n## 6. Form control:\nWe already created the user-form component to set it up in our routing.\n\nNow it's time to add some content to it.\n\n### Prerequesites\nWe are planning to implement via the Reactive Forms way.\nSo first we need to make sure we have all required imports in the app module:\n\n### File changes:\n\n#### Module\nHere we want to make sure that we have all the modules available in our form.  \n\n__app.module.ts__  \nAdd the angular ReactiveFormsModule and the following material imports to the app modules:  \n\n```typescript\n...\nimport { ReactiveFormsModule }   from '@angular/forms';\nimport { ...\n,MatInputModule, MatSelectModule, MatCardModule, MatNativeDateModule } from '@angular/material';\nimport {MatDatepickerModule} from '@angular/material/datepicker';\n...\nimports: [\n    ...\n    ReactiveFormsModule,\n    ...\n    MatInputModule,\n    MatSelectModule,\n    MatCardModule,\n    MatNativeDateModule,\n    MatDatepickerModule\n  ]\n...\n```\n\n__user-form.component.ts__:  \nMove to the user-form.component.ts file, there are quite some changes that we need to do here:\n\n#### Model \u0026 Service\nFirst we want to add the Model, the Service and we also want the service method to subscribe to the roleList observable:  \n```typescript\n...\nimport { RoleService } from '../service/role.service'\nimport { Role } from '../model/role.model';\nimport { User } from '../model/user.model';\n...\nexport class UserFormComponent implements OnInit {\n  roleList:Role[];\n  user:User = new User();\n\n  constructor(\n    private roleService: RoleService) { }  \n\n  ngOnInit() {\n      this.getRoleList();\n  }\n\n  getRoleList(): void {\n     this.roleService.getRoleList().subscribe(data =\u003e this.roleList = data);\n  }\n\n}\n...\n```\nWe now added a variable for the roleList that we will later on use for the dropdown options in the ui.\nWe added the user model that will be a representation of the user that is to be created.\nWe added the RoleService via Dependency Injection and we direclty call the getRoleList at ngOnInit.\n\n#### FormBuilder\nAs the next step we will import the FormBuilder and create the userForm controls based on the user data model:  \n```typescript\n...\nimport { FormBuilder, FormArray } from '@angular/forms';\n...\nexport class UserFormComponent implements OnInit {\n  userForm = this.fb.group({\n    username: [''],\n    password: [''],\n    email: [''],\n    roles: this.fb.array([\n      this.fb.group({\n        roleId: [''],\n        expiryDate: ['']\n      })\n    ])\n  });\n  constructor(\n    ...    \n    private fb: FormBuilder) { }\n    ...\n    get roles(): FormArray {\n    return this.userForm.get('roles') as FormArray;\n    }\n    ...\n    onSubmit(): void {\n      Object.assign(this.user,this.user,this.userForm.value);\n    }\n  }\n...\n```\n* The userForm reflects the same model as we have defined in the user.model.ts\n* We also added a getter method for the roles to make it easier to access them direclty as a FormArray\n* And we implemented the onSubmit() method that basically assigns the userForm to the user model\n\n####  FormArray\nNow we also want to be able to add and remove items of the FormArray roles.\n\n```typescript\n...\nexport class UserFormComponent implements OnInit {\n  ...\n  addUserRole(): void {\n  this.roles.push(this.fb.group({\n      roleId: [''],\n      expiryDate: ['']\n    }));\n  }\n  removeUserRole(i: number): void {\n    this.roles.removeAt(i);\n  }\n ...\n}\n...\n```\n* with this.roles we access the roles via the get method we defined and can use push and removeAt for adding/removing items.\n\n__user-form.component.html__:  \nWe also need to completly change the file.\nAdd the following:\n```html\n\u003cform novalidate [formGroup]=\"userForm\" (ngSubmit)=\"onSubmit()\"\u003e\n  \u003cmat-card\u003e\n    \u003cmat-form-field appearance=\"outline\"\u003e\n      \u003cmat-label\u003eusername\u003c/mat-label\u003e\n      \u003cinput matInput formControlName=\"username\"\u003e\n    \u003c/mat-form-field\u003e\n\n    \u003cmat-form-field appearance=\"outline\"\u003e\n      \u003cmat-label\u003epassword\u003c/mat-label\u003e\n      \u003cinput matInput type=\"password\" formControlName=\"password\"\u003e\n    \u003c/mat-form-field\u003e\n\n    \u003cmat-form-field appearance=\"outline\"\u003e\n      \u003cmat-label\u003eemail\u003c/mat-label\u003e\n      \u003cinput matInput formControlName=\"email\"\u003e\n    \u003c/mat-form-field\u003e\n  \u003c/mat-card\u003e\n  \u003cmat-card\u003e\n    \u003cdiv formArrayName=\"roles\"\u003e\n      \u003cdiv *ngFor=\"let userRole of roles.controls; let i=index\" [formGroupName]=\"i\"\u003e\n        \u003cmat-form-field appearance=\"outline\"\u003e\n          \u003cmat-label\u003erole\u003c/mat-label\u003e\n          \u003cmat-select formControlName=\"roleId\"\u003e\n            \u003cmat-option *ngFor=\"let roleItem of roleList\" [value]=\"roleItem.id\"\u003e\n              {{roleItem.name}}\n            \u003c/mat-option\u003e\n          \u003c/mat-select\u003e\n        \u003c/mat-form-field\u003e\n\n        \u003cmat-form-field appearance=\"outline\"\u003e\n          \u003cinput matInput [matDatepicker]=\"picker\" formControlName=\"expiryDate\"\u003e\n          \u003cmat-datepicker-toggle matSuffix [for]=\"picker\"\u003e\u003c/mat-datepicker-toggle\u003e\n          \u003cmat-datepicker #picker\u003e\u003c/mat-datepicker\u003e\n        \u003c/mat-form-field\u003e\n\n        \u003cbutton mat-raised-button (click)=\"removeUserRole(i)\"\u003e\n          \u003cmat-icon aria-label=\"remove role\"\u003ealarm\u003c/mat-icon\u003e\n        \u003c/button\u003e\n\n      \u003c/div\u003e\n      \u003cbutton mat-raised-button (click)=\"addUserRole()\"\u003e\n        \u003cmat-icon aria-label=\"add role\"\u003eadd\u003c/mat-icon\u003e\n      \u003c/button\u003e\n    \u003c/div\u003e\n  \u003c/mat-card\u003e\n    \u003cmat-card\u003e\n  \u003cbutton mat-raised-button type=\"submit\"\u003eSubmit\u003c/button\u003e\n    \u003c/mat-card\u003e\n\u003c/form\u003e\n\n\u003cpre\u003e{{userForm.value | json}}\u003c/pre\u003e\n\u003cpre\u003e{{user | json}}\u003cpre\u003e\n```\n\nLet's go through the most important points:\n\n####  Form setup\n```html\n\u003cform novalidate [formGroup]=\"userForm\" (ngSubmit)=\"onSubmit()\"\u003e\n```  \n* we add novalidate to disable standard validation\n* as we imported the ReactiveFormsModule we now have access to its directives to bind the data\n* with this we add [formGroup]=\"userForm\" as a property binding to our userForm group from the component\n* we also add a event binding for the ngSubmit to our onSubmit() methon in the component\n\n####  Input fields\n```html\n...\n\u003cinput matInput formControlName=\"username\"\u003e\n...\n\u003cinput matInput type=\"password\" formControlName=\"password\"\u003e\n...\n\u003cinput matInput formControlName=\"email\"\u003e\n...\n```  \n* here we bind the form controls username, password and email to the input fields\n\n#### Form Array  \n```html\n...\n\u003cdiv formArrayName=\"roles\"\u003e\n  \u003cdiv *ngFor=\"let userRole of roles.controls; let i=index\" [formGroupName]=\"i\"\u003e\n    ...\n  \u003c/div\u003e\n  ...\n\u003c/div\u003e\n...\n```\n* bind the form array to roles in the div that surrounds the ngFor and its content\n* create another div that iterates through all controls (in this case the formgroup with no defined name) of the roles array - make sure to user roles.controls as we cannot iterate though a FormArray itself.\n* bind the [formGroupName] to the index of the iteration -\u003e this will enable a clear seperation between the different indices.\n\n__select \u0026 input for the Form Array__  \n\nInside the form array we want to have a select(dropdown) and a date input field:\n```html\n...\n\u003cdiv formArrayName=\"roles\"\u003e\n  \u003cdiv *ngFor ...\u003e\n    \u003cmat-select formControlName=\"roleId\"\u003e\n      \u003cmat-option *ngFor=\"let roleItem of roleList\" [value]=\"roleItem.id\"\u003e\n        {{roleItem.name}}\n      \u003c/mat-option\u003e\n    \u003c/mat-select\u003e\n    ...\n    \u003cinput matInput [matDatepicker]=\"picker\" formControlName=\"expiryDate\"\u003e\n    ...\n  \u003c/div\u003e\n  ...\n\u003c/div\u003e\n...\n```\n\n* bind the roleId to the form control\n* use another ngFor to iterate over the complete roleList - this list comes from the role service and is not\nbound to the form control or the user model -\u003e its only used to populate the available options in the select!\n* however we bind the [value] to the roleItem.id - that is the value we want to have as the roleId in the form control -\u003e so the binding comes from the select formControlName ove the option [value].\n* as another input we also add a date field bound to the form contol expiryDate.\n\n__events for the Form Array__  \nAdding buttons to remove and add roles:\n\n```html\n...\n\u003cdiv formArrayName=\"roles\"\u003e\n  \u003cdiv *ngFor ...\u003e\n    ...\n    \u003cbutton mat-raised-button (click)=\"removeUserRole(i)\"\u003e...\u003c/button\u003e\n  \u003c/div\u003e\n  \u003cbutton mat-raised-button (click)=\"addUserRole()\"\u003e...\u003c/button\u003e\n\u003c/div\u003e\n...\n```\n\n* bind the (click) in the ngFor to the removeUserRole and pass over the index\n* bind the (click) outside the ngFor to the addUserRole\n\n__submit__  \nAdd the following to submit (via the onSumbit() method):\n```html\n...\n\u003cbutton mat-raised-button type=\"submit\"\u003eSubmit\u003c/button\u003e\n...\n```\n\n__preview__  \nBy adding the following code to the end to the html:\n```html\n...\n\u003cpre\u003e{{userForm.value | json}}\u003c/pre\u003e\n\u003cpre\u003e{{user | json}}\u003cpre\u003e\n```\n* we are now able to see a representation of the userForm and also the user model at the bottom of the page.\n\n\n## 7. Form validation\nWith the setup we have, the validation is not a big problem anymore.\n\nLet's add some basic validation rules.\nWe add the following validation rules \u0026 respective validation messages:\n- username -\u003e mandatory\n- password -\u003e mandatory \u0026 min 8 characters\n- email -\u003e valid email (inbuild validation)\n- roleId -\u003e mandatory\n\n### File Changes\n#### Validation ts\n__user-form.component.ts__  \nhere is the code:\n```typescript\n...\nimport { ..., Validators } from '@angular/forms';\n...\nuserForm = this.fb.group({\n  username: ['', Validators.required],\n  password: ['', [Validators.required, Validators.minLength(8)]],\n  email: ['', Validators.email],\n  roles: this.fb.array([\n    this.fb.group({\n      roleId: ['', Validators.required],\n      expiryDate: ['']\n    })\n  ])\n});\n\nuserFormValidationMessages = {\n  username: [\n    { type: 'required', message: 'Username is required' }\n  ],\n  password: [\n    { type: 'required', message: 'Password is required' },\n    { type: 'minlength', message: 'Password must be at least 8 characters long' }\n  ],\n  email: [\n    { type: 'email', message: 'Enter a valid email' }\n  ],\n  roleId: [\n    { type: 'required', message: 'Role is required' }\n  ]\n};\n```\n* added Validators into the FormBuilder controls\n* added userFormValidationMessages for each control that we want to validate\n\n#### Validation html\nLet's add the validation messages into our html file using mat-error and ng directives.\nThere are multiple metadata properties in the form controls that we can use (on form controls and also form groups):\n\n* __untouched__ True if control has not lost focus yet.\n* __touched__ True if control has lost focus.\n* __pristine__ True if user has not interacted with the control yet.\n* __dirty__ True if user has already interacted with the control.\n* __valid__ True if the control passes all validation rules.\n* __invalid__ True if the control does not pass all validation rules.\n* __hasError(\u003cvalidation_rule\u003e)__ True if the control is in error for the given validation rule  \n...\n\nIn the html file we add the required attribute to all required form fields: We also add the \u003cmat-error\u003e tag twice - first one to iterate through all validating messages for the given form field - the second one to display the error message(s) that are defined via ngIf:\n\nExample for username:\n```html\n...\n\u003cinput matInput formControlName=\"username\" required\u003e\n\u003cmat-error *ngFor=\"let validation of userFormValidationMessages.username\"\u003e\n  \u003cmat-error *ngIf=\"userForm.get('username').hasError(validation.type)\n  \u0026\u0026 (userForm.get('username').dirty\n  || userForm.get('username').touched)\"\u003e{{validation.message}}\u003c/mat-error\u003e\n\u003c/mat-error\u003e\n\n\u003cbutton mat-raised-button type=\"submit\" [disabled]=\"userForm.invalid\"\u003eSubmit\u003c/button\u003e\n...\n```\nContinue for the other fields using the same logic.\n\nFor the FormArray fields there is a slightly different logic - we do not user userForm.get(), instead we use userRole.get() as this is part of the iteration we use in the parent ngFor.\n```html\n...\n\u003cdiv *ngFor=\"let userRole of roles.controls; let i=index\" [formGroupName]=\"i\"\u003e\n  ...\n  \u003cmat-error *ngFor=\"let validation of userFormValidationMessages.roleId\"\u003e\n    \u003cmat-error *ngIf=\"userRole.get('roleId').hasError(validation.type)\n    \u0026\u0026 (userRole.get('roleId').dirty\n    || userRole.get('roleId').touched)\"\u003e{{validation.message}}\u003c/mat-error\u003e\n  \u003c/mat-error\u003e\n  ...\n\u003c/div\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprincev%2Fng-mat-form","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprincev%2Fng-mat-form","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprincev%2Fng-mat-form/lists"}