I'm trying to implement the Angular Material Stepper functionality in our application. Based on the documentation here I came up with the following solution:
civilliability-proposal-detail.component.html
<form [formGroup]="formGroup">
<mat-horizontal-stepper labelPosition="bottom" formArrayName="formArray" #stepper>
<mat-step formGroupName="0" [stepControl]="formArray?.get([0])" [editable]="true">
<div>
<ng-template matStepLabel>{{ 'proposals.details.civilLiability.stepper.details' | translate }}</ng-template>
<app-civilliability-step1 [model]="model.details"></app-civilliability-step1>
<button mat-button matStepperNext type="button">Next</button>
</div>
</mat-step>
<mat-step formGroupName="1" [stepControl]="formArray?.get([1])" [editable]="true">
<div>
<ng-template matStepLabel>{{ 'proposals.details.civilLiability.stepper.antecedents' | translate }}</ng-template>
<!-- <app-civilliability-step2 [model]="model.questionnaire"></app-civilliability-step2> -->
<button mat-button matStepperPrevious type="button">Back</button>
<button mat-button matStepperNext type="button">Next</button>
</div>
</mat-step>
</mat-horizontal-stepper>
</form>
civilliability-proposal-detail.component.ts
get formArray(): AbstractControl | null {
return this.formGroup.get('formArray');
}
constructor(private formBuilder: FormBuilder) {}
ngOnInit() {
this.buildForms();
}
buildForms() {
this.formGroup = this.formBuilder.group({
formArray: this.formBuilder.array([this.buildDetailsForm(), this.buildQuestionnaireForm()])
});
}
buildDetailsForm(): FormGroup {
if (typeof this.model === 'undefined') {
this.model = getEmptyCivilLiabilityRequest();
}
const formGroup = this.formBuilder.group({
horses: new FormControl(this.model.details.horses, Validators.min(0)),
properties: new FormControl(this.model.details.properties, Validators.min(0)),
garages: new FormControl(this.model.details.garages, Validators.min(0)),
...
});
return formGroup;
}
buildQuestionnaireForm(): FormGroup {
const formGroup = this.formBuilder.group({});
return formGroup;
}
civilliability-step1.component.html
<form [formGroup]="formGroup">
<section class="row">
<section class="col-md-4 full-width-form">
<mat-form-field>
<mat-label>{{ 'proposals.details.civilLiability.horses' | translate }}</mat-label>
<input type="number" matInput formControlName="horses" />
<mat-error>{{ formGroup.controls['horses'].getError('server-error') }}</mat-error>
</mat-form-field>
</section>
<section class="col-md-4 full-width-form">
<mat-form-field>
<mat-label>{{ 'proposals.details.civilLiability.terrainsWithTrees' | translate }}</mat-label>
<input type="number" matInput formControlName="terrainsWithTrees" />
<mat-error>{{ formGroup.controls['terrainsWithTrees'].getError('server-error') }}</mat-error>
</mat-form-field>
</section>
<section class="col-md-4 full-width-form">
<mat-form-field>
<mat-label>{{ 'proposals.details.civilLiability.garages' | translate }}</mat-label>
<input type="number" matInput formControlName="garages" />
<mat-error>{{ formGroup.controls['garages'].getError('server-error') }}</mat-error>
</mat-form-field>
</section>
</section>
</form>
Based on this I get a bunch of errors which I think are related to the fact that I'm using child components in my form, but I'm not quite sure how to tackle this. So, any suggestions?
I've also read somebody not using the formArrayName
in the stepper, but I can't seem to find this example anymore, so can't test if that works or not.
Instead of using a form array, I would recommend declaring a form group in each individual step component. Here is how I have done it: