Skip to content

Instantly share code, notes, and snippets.

@jhades
Last active March 30, 2023 09:27
Show Gist options
  • Save jhades/a8a16ac802db0bdf0e38953fbbaa05dc to your computer and use it in GitHub Desktop.
Save jhades/a8a16ac802db0bdf0e38953fbbaa05dc to your computer and use it in GitHub Desktop.
Angular Form Array: Complete Guide - blog.angular-university.io/angular-form-array/
form = this.fb.group({
title: ['', {
validators: [
Validators.required,
Validators.minLength(5),
Validators.maxLength(60)
],
asyncValidators: [courseTitleValidator(this.courses)],
updateOn: 'blur'
}],
releasedAt: [new Date(), Validators.required],
category: ['BEGINNER', Validators.required],
downloadsAllowed: [false, Validators.requiredTrue],
longDescription: ['', [Validators.required, Validators.minLength(3)]]
});
@Component({
selector: 'form-array-example',
templateUrl: 'form-array-example.component.html',
styleUrls: ['form-array-example.component.scss']
})
export class FormArrayExampleComponent {
form = this.fb.group({
... other form controls ...
lessons: this.fb.array([])
});
constructor(private fb:FormBuilder) {}
get lessons() {
return this.form.controls["lessons"] as FormArray;
}
}
<button mat-mini-fab (click)="addLesson()">
<mat-icon class="add-course-btn">add</mat-icon>
</button>
addLesson() {
const lessonForm = this.fb.group({
title: ['', Validators.required],
level: ['beginner', Validators.required]
});
this.lessons.push(lessonForm);
}
deleteLesson(lessonIndex: number) {
this.lessons.removeAt(lessonIndex);
}
<h3>Add Course Lessons:</h3>
<div class="add-lessons-form" [formGroup]="form">
<ng-container formArrayName="lessons">
<ng-container *ngFor="let lessonForm of lessons.controls; let i = index">
<div class="lesson-form-row" [formGroup]="lessonForm">
<mat-form-field appearance="fill">
<input matInput
formControlName="title"
placeholder="Lesson title">
</mat-form-field>
<mat-form-field appearance="fill">
<mat-select formControlName="level"
placeholder="Lesson level">
<mat-option value="beginner">Beginner</mat-option>
<mat-option value="intermediate">Intermediate</mat-option>
<mat-option value="advanced">Advanced</mat-option>
</mat-select>
</mat-form-field>
<mat-icon class="delete-btn" (click)="deleteLesson(i)">
delete_forever</mat-icon>
</div>
</ng-container>
</ng-container>
<button mat-mini-fab (click)="addLesson()">
<mat-icon class="add-course-btn">add</mat-icon>
</button>
</div>
@Component({
selector: 'form-array-example',
templateUrl: 'form-array-example.component.html',
styleUrls: ['form-array-example.component.scss']
})
export class FormArrayExampleComponent {
form = this.fb.group({
... other form controls ...
lessons: this.fb.array([])
});
constructor(private fb:FormBuilder) {}
get lessons() {
return this.form.controls["lessons"] as FormArray;
}
addLesson() {
const lessonForm = this.fb.group({
title: ['', Validators.required],
level: ['beginner', Validators.required]
});
this.lessons.push(lessonForm);
}
deleteLesson(lessonIndex: number) {
this.lessons.removeAt(lessonIndex);
}
}
@BrunoPicolo
Copy link

BrunoPicolo commented Sep 21, 2022

For me the error disappears by casting the lessonsForm to FormGroup. To do this I created a method to do the casting and used it in the template.

In the template: <div class="lesson-form-row" [formGroup]="toFormGroup(lessonForm)">

In the class: toFormGroup = (form: AbstractControl) => form as FormGroup;

@gmurimi
Copy link

gmurimi commented Feb 17, 2023

I am wondering the same

@rofrol
Copy link

rofrol commented Mar 30, 2023

The error Type 'AbstractControl<any, any>' is missing the following properties from type 'FormGroup<any>' happens when you have in tsconfig.json:

  "angularCompilerOptions": {
    "strictTemplates": true
  },

Solution with pipe (I couldn't manage to make it work with generic pipe like in https://stackoverflow.com/a/69466380/588759):

import { Pipe, PipeTransform } from '@angular/core';
import { AbstractControl, FormGroup } from '@angular/forms';

/**
 * https://stackoverflow.com/a/72517767/588759
 * https://stackoverflow.com/a/67059770/588759
 */

@Pipe({
  name: 'formGroup',
})
export class FormGroupPipe implements PipeTransform {
  transform(value: AbstractControl): FormGroup<(typeof value)['value']> {
    return value as FormGroup<(typeof value)['value']>;
  }
}

and use as [formGroup]="lessonForm | formGroup"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment