3
votes

I am stuck with animating the step change of the Angular material custom stepper using the CDK. I have followed the tutorial on how to implement the custom stepper.

I have the demo here

My template looks like:

<section class="container">
 <header>
    <h2>Step {{selectedIndex + 1}}/{{steps.length}}</h2>
    <div>
      <button class="pure-button" cdkStepperPrevious>&larr;</button>
      <button
      class="pure-button"
      *ngFor="let step of steps; let i = index;"
      [ngClass]="{'pure-button-primary': selectedIndex === i}"
      (click)="onClick(i)"
  >
    Step {{i + 1}}
      </button>
      <button class="pure-button" cdkStepperNext>&rarr;</button>
     </div>
   </header>

 <div [@stepTransition]="_getAnimationDirection(current)" *ngFor="let step of _steps; let i = index">
  <div  [ngTemplateOutlet]="selected.content"></div>
  </div>

</section>

And my component TS file look like:

import { Component, OnInit } from '@angular/core';
import { CdkStepper } from '@angular/cdk/stepper';
import {
     trigger,
     state,
     style,
     animate,
     transition,
 } from '@angular/animations';

 @Component({
   selector: 'app-my-stepper',
   templateUrl: './my-stepper.component.html',
   styleUrls: ['./my-stepper.component.css'],
   providers: [{ provide: CdkStepper, useExisting: MyStepperComponent }],
  animations: [trigger('stepTransition', [
      state('previous', style({transform: 'translate3d(-100%, 0, 0)', visibility: 'hidden'})),
      state('current', style({transform: 'none', visibility: 'visible'})),
      state('next', style({transform: 'translate3d(100%, 0, 0)', visibility: 'hidden'})),
      transition('* => *', animate('500ms cubic-bezier(0.35, 0, 0.25, 1)'))
   ])]
})
 export class MyStepperComponent extends CdkStepper implements OnInit {
    current = 0;

    onClick(index: number): void {
    this.current = index;
     this.selectedIndex = index;
  }

  ngOnInit() {   
      console.log(this._getFocusIndex())
   }

}

The animation only works for the last step, the reason is that the animation state(previous, current, next)value does not change onClick.

How can I achieve this? any idea is much appreciated, thanks.

UPDATE Check the stackblitz repo for the latest code

1

1 Answers

1
votes

In your stackblitz demo you have the following html:

<div *ngFor="let step of _steps; let i = index"
     [@stepTransition]="_getAnimationDirection(i)" 
     [attr.tabindex]="selectedIndex === i ? 0 : null"
     [id]="_getStepContentId(i)"
     (@stepTransition.done)="_animationDone.next($event)"
     [attr.aria-labelledby]="_getStepLabelId(i)"
     [attr.aria-expanded]="selectedIndex === i">
    <ng-container [ngTemplateOutlet]="selected.content">
    </ng-container> 
</div>

I think the main problem here is in this line: <div [ngTemplateOutlet]="selected.content"></div>

You create a div for each step, and every div will contain the same selected.content. So all the styles applied to the parent div (transform and visibility) will also apply to the selected.content which will lead to an ambiguous behavior.

If you replace it with <div [ngTemplateOutlet]="step.content"></div>, you will start seeing all your images, but they will be placed one under another.

This happens because of the css visibility property:

it shows or hides an element without changing the layout of a document.

So I suggest you to add position: absolute; to your steps.

Take a look at the stackblitz with these improvements