Angular Material Stepper 'Paginate'
Asked Answered
C

3

5

I have many steps in my stepper, so i want to divide it in two parts, i.e.

When users goes inside wizard, the stepper header shows only 1--2--3--4, then, when step 4 is finished, and the user goes into step 5, the header shows 5--6--7--8, and so on for next steps.

Do you know any way to do this?

Thanks in advance.

Edit:

I tried using *ngIf to hide/unhide steps, but it does remove those steps from the stepper array, so entered information losts when step hides.

Here is my *ngIf approach: https://stackblitz.com/edit/angular-material2-beta-kknvx9

Also, tried a similar approach with [hidden], but it does not work at all.

Christinchristina answered 30/12, 2019 at 16:22 Comment(2)
what do you think about having two steppers instead of one, both with 4 steps?Excurrent
Try hiding them using display:none instead of ngIfSomite
S
4

The problem is that the mat-step changes to mat-step-header when it renders and any custom class or attribute on it will be gone.

The following code works but it's messy. The best solution is to find another wizard component that has what you need or to submit a request for Material developers on GitHub to add a hidden flag to the mat-step.

StackBlitz

Class:

export class AppComponent implements OnInit, AfterViewInit{
  private ngVersion: string = VERSION.full;

  MAX_STEP = 7;

  @ViewChild('stepper') private myStepper: MatStepper;
  step: number = 0;
  page:number = 0;

  constructor() {}

  ngOnInit() {}

  ngAfterViewInit() {
    this.rerender();
  }

  goBack() {
    if (this.step > 0) {
      this.step--;
      this.myStepper.previous();
    }
    this.page = this.step > 3 ? 1 : 0;
    this.rerender();
  }

  goForward() {
    if(this.step < this.MAX_STEP) {
      this.step++;
      this.myStepper.next();
    }
    this.page = this.step > 3 ? 1 : 0;
    this.rerender() 
  }

  private rerender() {

    let headers = document.getElementsByTagName('mat-step-header');
    let lines = document.getElementsByClassName('mat-stepper-horizontal-line');

    for (let h of headers) {
      if (this.page === 0) {
        if (Number.parseInt(h.getAttribute('ng-reflect-index')) > 3) {
          h.style.display = 'none';
        }
        else {
          h.style.display = 'flex';
        }
      }
      else if (this.page === 1) {
        if (Number.parseInt(h.getAttribute('ng-reflect-index')) < 4) {
          h.style.display = 'none';
        }
        else {
          h.style.display = 'flex';
        }
      }
    }

    for (let i = 0; i < lines.length; i++) {
      if (this.page === 0) {
        if (i > 2) {
          lines[i].style.display = 'none';
        }
        else {
          lines[i].style.display = 'block';
        }
      }
      else if (this.page === 1) {
        if (i < 4) {
          lines[i].style.display = 'none';
        }
        else {
          lines[i].style.display = 'block';
        }
      }
    }

  }

}

View:

<div class="solution">

  <!--------------------------------------------------------------------------------------->
  <mat-horizontal-stepper #stepper>
    <mat-step>
      Step 1
    </mat-step>
    <mat-step>
      Step 2
      <input matInput placeholder="Address" required>
    </mat-step>
    <mat-step>
      Step 3
    </mat-step>
    <mat-step>
      Step 4
    </mat-step>
    <mat-step>
      Step 5
    </mat-step>
    <mat-step>
      Step 6
      <input matInput placeholder="Address" required>
    </mat-step>
    <mat-step>
      Step 7
    </mat-step>
    <mat-step>
      Step 8
    </mat-step>
    <!-- one option -->
  </mat-horizontal-stepper>

  <!-- second option -->
  <div>
    <button (click)="goBack()" type="button" [hidden]="step === 0">Back</button>
    <button (click)="goForward()" type="button" [hidden]="step === MAX_STEP">Next</button>
  </div>
  <!--------------------------------------------------------------------------------------->
  Step: {{step}}
  <br>
  Page: {{page}}

</div>
Sphenic answered 2/1, 2020 at 12:30 Comment(1)
Thank you very much! The request is already done: github.com/angular/components/issues/12166 but marked as low-priority :(Christinchristina
P
2

I got the same problem and an got a solution for a scrollable list.

By setting .mat-horizontal-stepper-header-container to overflow: scroll and .mat-horizontal-stepper-header to overflow: visbile you will get a non squashed and scrollable header bar. Going to the next step (or scrolling the bar) can be easily done programmatically.

enter image description here

Pachydermatous answered 29/9, 2020 at 18:9 Comment(0)
B
2

I was working on the similar problem recently and with a bit of a reference from this answer https://mcmap.net/q/1977927/-angular-material-stepper-39-paginate-39 by Sasan, I tried to write a more generalized version of the code. I've added a pagination option in the stepper by taking into account min and max index of the steps we want to display at any time. The rest of the steps which don't follow in between this range, have the display as "none".

Stepper With Pagination

You can refer to the stackblitz over here: https://stackblitz.com/edit/angular-mat-stepper-paginator?file=src/app/stepper-paginator1/stepper-paginator1.component.ts

If you're interested in a more detailed explanation, you can check out my blog over here: https://madhura-gore.medium.com/angular-material-stepper-with-pagination-b9e1b091b8f6

Brader answered 31/3, 2021 at 9:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.