2

I need an checked solution of Stepper component for Angular 7, that works with Angular routing.

Not a Material Design Stepper - it does work well for simple forms, but not routing.

What I tried to do, with <mat-horizontal-stepper>, was something like this:

component.html:

<mat-horizontal-stepper (selectionChange)="selectionChanged($event)" [linear]="true">
    <mat-step *ngFor="let step of steps; let i = index" [label]="step.title">
        <router-outlet *ngIf="i === selectedStepIndex"></router-outlet>
    </mat-step>
</mat-horizontal-stepper>

component.ts:

public selectedStepIndex: number = 0;

selectionChanged(event: any) {
    this.selectedStepIndex= event.selectedIndex;
    const url = '/some-path/' + this.links[this.selectedStepIndex].path;
    this.router.navigate([url]);//using -> private router: Router
}

However, I can not navigate back for some reason. Stepper tries to navigate back, but it shows the same page, unless it is the first page of stepper (i = 0).

I would be greatful for any recommendation (and maybe working example), or a detailed information about how to achive this with <mat-horizontal-stepper>.

Wojciech X
  • 285
  • 1
  • 3
  • 15

3 Answers3

6

Alright! I have figured it out :)

It looks like <mat-horizontal-stepper> needs some time to reaload showed step, when it comes to <router-outlet> - so I had to manually force him to wait. Do something like this, and it will work good enough:

component.html:

<mat-horizontal-stepper (selectionChange)="selectionChanged($event)" [linear]="true">
    <mat-step *ngFor="let step of steps; let i = index" [label]="step.title">
        <div *ngIf="loadingStep">
            <mat-spinner></mat-spinner>
        </div>
        <div *ngIf="!loadingStep">
            <router-outlet *ngIf="i === selectedStepIndex"></router-outlet>
        </div>
    </mat-step>
</mat-horizontal-stepper>

component.ts:

public selectedStepIndex: number = 0;
public loadingStep: boolean = false;

selectionChanged(event: any) {
    this.selectedStepIndex = event.selectedIndex;
    if (event.previouslySelectedIndex > event.selectedIndex) {
        this.loadingStep = true;
        //Wait 1 sec. before showing the step
        setTimeout(() => {
            this.navigate();
            this.loadingStep = false;
        }, 1000);
    } else {
        this.navigate();
    }
}

private navigate(): void {
    const url = '/some-path/' + this.links[this.selectedStepIndex].path;
    this.router.navigate([url]);//using -> private router: Router
}

It is not perfect, but it is good enough for me :))

Wojciech X
  • 285
  • 1
  • 3
  • 15
3

You misunderstand the <router-oulet>. It display the component matching the routes you define in your routing module. So if the <mat-step> does not trigger URL changes or route navigation, the <router-oulet> displays the same component:

You can achieve your intent with logic like this:

Add [routerLink] directive to <mat-step>:

<mat-horizontal-stepper (selectionChange)="selectionChanged($event)" [linear]="true">
    <mat-step *ngFor="let step of steps; let i = index" [routerLink]="['/step' + i]" [label]="step.title">
        <router-outlet *ngIf="i === selectedStepIndex"></router-outlet>
    </mat-step>
</mat-horizontal-stepper>

Define the component's route in your routing module :

const routes: Routes = [
      //Just an example for the logic i used  
      { path: 'step0', component: StepOComponent },
      { path: 'step1', component: Step1Component },
      { path: 'step2', component: Step2Component },
    ]
 }
];
rmcsharry
  • 5,363
  • 6
  • 65
  • 108
Ethan Vu
  • 2,911
  • 9
  • 25
  • Sorry, question was not complete, edited it now. As yoy can see, I am using `.navigate([url])` method in my code behind. And I tried to change it to `[routerLink]`, it still does not work. – Wojciech X Aug 08 '19 at 08:41
1

This work for me

<mat-horizontal-stepper linear #stepper (selectionChange)="selectionChanged($event)">
    <mat-step [stepControl]="formFirst" [editable]="true">
        <ng-template matStepLabel>Product details</ng-template>
        <router-outlet *ngIf="0 === selectedStepIndex"></router-outlet>
    </mat-step>
    <mat-step>
        <ng-template matStepLabel>Key features</ng-template>
        <router-outlet *ngIf="1 === selectedStepIndex"></router-outlet>
    </mat-step>
</mat-horizontal-stepper>

Function

  selectionChanged($event): void {
    this.selectedStepIndex = $event.selectedIndex;
    switch ($event.selectedIndex) {
      case 0:
        this.router.navigate(['./'], { relativeTo: this.route });
        break;
      case 1:
        this.router.navigate(['./feature'], { relativeTo: this.route });
        break;
    }
  }
San Jaisy
  • 15,327
  • 34
  • 171
  • 290