Using separate components in a linear mat-horizontal-stepper

Michael picture Michael · Nov 15, 2017 · Viewed 12.7k times · Source

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.

Answer

San Jaisy picture San Jaisy · Nov 27, 2018

Here is the solution that work for me.

<mat-horizontal-stepper [linear]="true" #stepper>
  <mat-step [stepControl]="selectAdvType">
    <ng-template matStepLabel>
      <div class="text-center">
        <mat-icon>queue_play_next</mat-icon><br /><span>Select Adv Type</span>
      </div>
    </ng-template>
    <app-advertisement-type></app-advertisement-type>
  </mat-step>
  <mat-step [stepControl]="selectAdvType">
    <ng-template matStepLabel>
      <div class="text-center">
        <mat-icon>directions_car</mat-icon><br /><span>Select Car</span>
      </div>
    </ng-template>
    <app-select-car-adv></app-select-car-adv>
  </mat-step>
  <mat-step>
    <ng-template matStepLabel>
      <div class="text-center">
        <mat-icon>description</mat-icon><br /><span>Select Features</span>
      </div>
    </ng-template>
    <div>
      <button mat-button matStepperPrevious>Back</button>
      <button mat-button (click)="stepper.reset()">Reset</button>
    </div>
  </mat-step>
</mat-horizontal-stepper>

Parent Ts file

@Component({
  selector: 'app-customer.create.advertisement',
  templateUrl: './customer.create.advertisement.component.html',
  styleUrls: ['./customer.create.advertisement.component.scss']
})
export class CustomerCreateAdvertisementComponent implements OnInit {
  isLinear = false;
  selectAdvType: FormGroup;
  constructor(private _formBuilder: FormBuilder) { }
  ngOnInit() {
    this.selectAdvType = this._formBuilder.group({
      firstCtrl: ['', Validators.required]
    });
  }
}

Child component

<form [formGroup]="firstFormGroup">
    <ng-template matStepLabel>Fill out your name</ng-template>
    <mat-form-field>
        <input matInput placeholder="Last name, First name" formControlName="firstCtrl" required>
    </mat-form-field>
    <div>
        <button mat-button matStepperNext>Next</button>
    </div>
</form>


@Component({
  selector: 'app-advertisement-type',
  templateUrl: './advertisement-type.component.html',
  styleUrls: ['./advertisement-type.component.scss']
})
export class AdvertisementTypeComponent implements OnInit {
  firstFormGroup: FormGroup;
  constructor(private _formBuilder: FormBuilder) { }

  ngOnInit() {
    this.firstFormGroup = this._formBuilder.group({
      firstCtrl: ['', Validators.required]
    });
  }

}