2

I am doing a vertical stepper with angular material. The thing is that this stepper puts the content of each step below the step header, so if there are many steps it looks awfull because you have to scroll.

My idea is to separate the headers from the content so it will look more like a sidenav but with the angular material functionality.

Here you there is what i have by now: actual stepper where the content appears below the header

And here there is what i want wanted stepper where the content is in the center of the page and the steps headers in the side

I have tried by editing the headers like this:

mat-step-header{
  display: flex ;
  justify-content: flex-end ;
}

But it isn't working.

wata
  • 76
  • 4

2 Answers2

2

I am not sure if this works same on stepper, but I did similar thing on tabs. I used service to exchange data between components. If you use the content and header in same place you could try to have 2 steppers.

1 for header and second for content. You should be able to hide header for second tab and content for first tab. On first tab you can use selectedIndex bound to a variable in typescript. So that once you change the variable it will go to that step. to change the variable you can make a function selectionChange that will take step event from the header-stepper and change the variable. From what I saw stepper is similar to tabs. so this should work. Hope this helps.

header stepper (selectionChange)="selectionChange($event)"

content stepper [(selectedIndex)]="selectedIndex"

GreedyAi
  • 2,709
  • 4
  • 29
  • 55
0

Here's an approach I used for this, by projecting the content of each step into another component. This avoids using a service, event handlers, etc.

In my case I wanted to project the current step into an Expansion Panel alongside the stepper. This example illustrates how you can populate the various sections of this from the stepper, using buttons in the panel's action row to navigate the stepper:

  <mat-stepper #stepper orientation="vertical">
    <ng-template #expansionPanelHeader>
      <ng-container [ngTemplateOutlet]="stepper.selected?.stepLabel.template"></ng-container>                
    </ng-template>

    <ng-template #expansionPanelContent>
      <ng-container [ngTemplateOutlet]="stepper.selected?.content"></ng-container>
    </ng-template>

    <ng-template #expansionPanelActionRow>
      <button mat-button matStepperPrevious>Back</button>
      <button mat-button matStepperNext>Next</button>
    </ng-template>

    <mat-step>
      <ng-template matStepLabel>Step 1</ng-template>
      <ng-template matStepContent>
        This is the content of step 1.
      </ng-template>
    </mat-step>

    <mat-step>
      <ng-template matStepLabel>Step 2</ng-template>
      <ng-template matStepContent>
        This is the content of step 2.
      </ng-template>
    </mat-step>
  </mat-stepper>

  <!-- The current step will be projected into this component -->
  <mat-expansion-panel>
    <mat-expansion-panel-header>
      <ng-container [ngTemplateOutlet]="expansionPanelHeader"></ng-container>
    </mat-expansion-panel-header>

    <ng-template matExpansionPanelContent>
      <ng-container [ngTemplateOutlet]="expansionPanelContent"></ng-container>
    </ng-template>

    <mat-action-row>
      <ng-container [ngTemplateOutlet]="expansionPanelActionRow"></ng-container>
    </mat-action-row>
  </mat-expansion-panel>

Unfortunately the only way I could find to prevent the stepper content from also appearing inside the stepper was this bit of CSS:

.mat-vertical-content-container {
  display: none !important;
}

The CSS needs to be placed either in a global .scss file or you will need to use ng-deep or some other such "solution". I prefer the former, scoped to the containing elements.

Chris Peacock
  • 4,107
  • 3
  • 26
  • 24