Search code examples
angularangular-materialangular-material2angular-material-stepper

Using separate components in a linear mat-horizontal-stepper


In Angular, is it possible to have a linear stepper where the individual steps are separate components? For example:

<mat-horizontal-stepper [linear]="isLinear">
    <mat-step [stepControl]="firstFormGroup" label="Some Form">
        <first-component></first-component>
    </mat-step>
    <mat-step [stepControl]="secondFormGroup" label="Another Form">
        <second-component></second-component>
    </mat-step>
    <mat-step [stepControl]="thirdFormGroup" label="Review">
        <third-component></third-component>
    </mat-step>
</mat-horizontal-stepper>

When I try this, I receive the following error upon hitting the matStepperNext button:

TypeError: Cannot read property 'invalid' of undefined.


Solution

  • Improving on @eliran-eliassy answer and @christian-steinmeyer question.

    Parent.Component.ts

      export class ParentComponent implements OnInit {
    
      isLinear = true;
      companyInfo: FormGroup;
    
      constructor(private _formBuilder: FormBuilder) {
    
      }
    
      ngOnInit() {
    
        this.companyInfo = this._formBuilder.group({
        });
    
      }
    
    }
    

    Parent.Component.html

    <mat-horizontal-stepper [linear]="isLinear" #stepper>
        <mat-step [stepControl]="companyInfo">
            <form [formGroup]="companyInfo">
                <ng-template matStepLabel>Fill out your name</ng-template>
                <app-company-info></app-company-info>
            </form>
            <div>
                <button mat-button matStepperNext>Next</button>
            </div>
        </mat-step>
    </mat-horizontal-stepper>
    

    Child.Component.ts -> this is the sub-form

    export class ChildComponent implements OnInit {
      form: FormGroup;
      subForm: FormGroup;
      constructor(
        private ctrlContainer: FormGroupDirective,
        private fb: FormBuilder
      ) {}
    
      ngOnInit() {
        this.subForm = this.fb.group({
          companyName: [null, [Validators.required]],
          numOfEmployees: [null, [Validators.required]]
        });
        
        this.form = this.ctrlContainer.form;
        this.form.addControl("company", this.subForm);
      }
    }
    

    Child.Component.html

    <div [formGroup]="subForm">
        <mat-form-field appearance="outline">
            <input matInput placeholder="Your Company Name" formControlName="companyName">
      </mat-form-field>
    </div>
    

    See this solution on stackblitz