Components: [Mat-Stepper] A few suggestions

Created on 11 Oct 2017  路  38Comments  路  Source: angular/components

Thanks for everyone who works on this project! I just upgraded to beta12 and am using the Stepper component now. I had a few proposals after using it for a bit. Please let me know what you think-I'd love to help contribute if we want any of these (:

  1. Mat-Stepper with horizontal/vertical as an input.

    • Use Case: I have a stepper that I want to toggle between horizontal/vertical for different screen aspect ratios but with the same content and steps. Currently I would need to create two separate components and toggle between the two which feels messy.

    • Proposal: Replace mat-vertical-stepper and mat-horizontal-stepper with mat-stepper that takes in an input to toggle between the two views

  2. SelectedIndex as input.
  3. Reset Stepper.

    • Use Case: I want to reset the stepper. I am using formGroup.reset() to reset each form, but this does not reset the visited states of each one of the steps.

    • Proposal: Some way of resetting the stepper component to the initial state: First step is selected, Forms are reset, None of the steps have been touched etc.

  4. Animate Height.

    • Use Case: Currently the steps slide right/left but the height of the stepper does not transition smoothly.

    • Proposal: Transition the height of the steps when changing from one step to the other

      Let me know what you think~

P3 cdstepper feature

Most helpful comment

disabled attribute is must have.
For example: we have 5 steps, step N is disabled by business logic. Then it should be gray out and not editable

All 38 comments

Would like to add one more suggestion here as well:
5. Disabled step. Or a way to add/remove steps.
- Use Case: Additional steps depending on what is being selected in previous steps. (like a wizard form).

I was able to add steps with something like this:

<mat-step *ngFor="let invForm of inventoryForms"
    [stepControl]="invForm.form" [label]="invForm.item.product.name">
</mat-step>

but if I go back to previous step, and change it so that these additional steps aren't required, and setting this.inventoryForms = [], the steps are not removed from the stepper.
Even wrapping it inside a <ng-container *ngIf="inventoryForms.length > 0"> did not work. 馃槥

I got a work-around, but is probably a bad idea 馃槄

  1. Make a reference to the stepper:
<mat-vertical-stepper #stepper></mat-vertical-stepper>
  1. Then, on the .ts side:
import { ViewChild } from '@angular/core';
import { MatVerticalStepper } from '@angular/material';

@ViewChild('stepper') stepper: MatVerticalStepper;

clearAdditionalForms(): void {
  this.inventoryForms = [];
  this.stepper._stateChanged(); // <- this : Marks the component to be change detected.
}

I would like to also leave a suggestion.

  1. Async step support. If each step is using it's own FormGroup, while using linear="true", the forms should be submitted before moving on to the next step.

disabled attribute is must have.
For example: we have 5 steps, step N is disabled by business logic. Then it should be gray out and not editable

Perhaps related to 4. Animate Height: having it animate the same way tab transitions where you see the current content slide out

Have any one a solution for suggestion 1? I tried quickly the same as in https://github.com/angular/material2/issues/8014 but ran into same issues.

As @jdeanwaite suggested async step support is critical.
I need to create 5 step process, when user clicks Next I'd like to submit data from that step to server, so that user can come back later and resume process.

linear="true" solves problem with disabling ability to move to next step before filling current, but there should be option to disable moving back. In my case when user submits current step by clicking Next he can't move back. Currently he can click Back button or use labels to navigate, so disable attribute is a must have for me.

I'd like to add: it would be nice if we could implement the dynamicHeight input that mat-tab-group has. I recently tried to replace a tab group with a stepper but I get painful layout problems due to each mat-step's height adapting to its content. Using a mat-tab-group I managed a workaround by setting dynamicHeight false. It seems the dynamicHeight behavior we have in mat-tab-group is something people are asking for anyway.

That is how to add steps dynamically -
<mat-step *ngIf="*expression*"></mat-step>

Anything new about disabling single steps?

EDIT

The way to disable steps is to add on the `' a _editable_ attribute.

<mat-step [editable]="myStepEditable">...</mat-step>

It worked for me because I need to handle disabled after the step was
completed already...

I don't know if this can prevent entering next steps...

Another great limitation of the steppers is that you cannot grow it to fill the entire parent space. I have a horizontal stepper and I want that the steps content cover all the available space (vertically). AFAIK there is no way to obtain this basic functionality. Any suggestion?

@AGPX are you using @angular/flex-layout?

@tonysamperi for sure, the problem is that the step contents are put inside a div with the class 'mat-horizontal-stepper-content'. Unfortunately, if you add the style 'height: 100%' this will grow all the steps including the hidden (not actived step), because they are hidden through the style 'visibility:hidden' instead of 'display:none' and so the previous hidden steps shift down the actived one. In addition, I found no example of what I wish to achieve.

@AGPX can you do a stackblitz?
You can fork mine...
https://stackblitz.com/edit/angular-mat-stepper-program

@tonysamperi sorry, but the proxy of my company don't allow me to use stackblitz (I will make this example from my home, later). I try, however, to explain my problem now.

Looking at the generated DOM of the stepper you have:

<div class="mat-horizontal-content-container">
   <div class="mat-horizontal-stepper-content ng-tns-c12-2 ng-trigger ng-trigger-stepTransition ng-star-inserted" role="tabpanel" id="cdk-step-content-0-0" aria-labelledby="cdk-step-label-0-0" aria-expanded="false" style="transform: translate3d(-100%, 0px, 0px); visibility: hidden;">

      my contents of step 1 go here...
   </div>
   <div class="mat-horizontal-stepper-content ng-tns-c12-2 ng-trigger ng-trigger-stepTransition ng-star-inserted" role="tabpanel" id="cdk-step-content-0-0" aria-labelledby="cdk-step-label-0-0" aria-expanded="false" style="transform: translate3d(-100%, 0px, 0px); visibility: visible;">

      my contents of step 2 go here...
   </div>
</div>

The only way to expand my content vertically in order to cover the entire vertical space is to add the style 'height: 100%' to 'mat-horizontal-stepper-content' and 'mat-horizontal-content-container' classes. Unfortunately, the 'mat-horizontal-stepper-content' is shared amongs all the steps and this will grow also the step 1 div (that is hidden). The result is that the step 2 content is shifted down.

@tonysamperi to prevent entering next step you must use FormBuilder and FormControl, with attached validators. This validators sets property completed for step and you can not step forward until step is not completed. Try to use custom validators:

this.registrationFormGroup = this._formBuilder.group({ confirmPasswordControl: ['', Validators.required, passwordMatchValidator], });
function passwordMatchValidator(g: FormGroup) { return g.get('passwordControl').value === g.get('confirmPasswordControl').value ? null : {'mismatch': true}; }

Set registrationFormGroup to mat-step and form inside it
<mat-step [stepControl]="registrationFormGroup" label="Step 1">
<form class="registration" [formGroup]="registrationFormGroup">

and confirmPasswordControl to input in the step
<input type="password" matInput placeholder="Confirm password" formControlName="confirmPasswordControl" required>

also you can setup completed property manually in ts code

<mat-horizontal-stepper #stepper>

@ViewChild('stepper') stepper: MatStepper;
nextStep(): void { this.stepper._steps.first.completed = true; this.stepper.next(); }

@vanmxpx Yeah, you're right.
But I think it's not practical if you are in this case:
If I wanted to send form data to a rest endpoint, and wait for its response to allow navigation, I should add a dummy (like a required hidden) input to invalidate the whole form. I think there should be some better option to prevent navigation through the stepper-header.

@AGPX I asked you to prepare a Stackblitz because I want to see how directives on the non-compiled, apply to the compiled.
And then think to some hacky rule in the styles.css to overcome your issue (But still, if strictly necessary).

@tonysamperi if i understand you right, you can go like this:
setup steps not completed by default in html <mat-step label="袩芯写锌懈褋泻邪" [completed]="false">
and set step 'completed' after a server response. this.stepper.selected.completed = true;. This not required any hacks with inputs.
Look throw stackblitz

@tonysamperi I have updated your sample in Stackblitz (from my home):

https://stackblitz.com/edit/angular-mat-stepper-program-8dkmen

Note that my example works if you try to replace the style 'visibility:hidden' with 'display:none' (for example from browser's DOM inspector) in all the divs with class 'mat-horizontal-stepper-content'. I'm not sure why 'visibility' was preferred over 'display', there is any drawback using it?

@vanmxpx thanks. Didn't know about the "complete" attr...
It could be even easier then...

HTML

<mat-step label="袩芯写锌懈褋泻邪" [completed]="completed">
      <button (click)="completed()">COMPLETE</button>
</mat-step>

TS

completed = false;

complete(){
     this.completed = true;
}

https://stackblitz.com/edit/mat-step-complete

@AGPX taking a look right now! I'm in CET 馃憤

@tonysamperi eh... the div should cover the entire vertical space...

@AGPX sorry, it did when I posted...maybe I didn't save...

@tonysamperi thank you very much, it works! A bit tricky though, I think that this should be supported natively by the stepper component. Anyway, thanks again!

@tonysamperi @AGPX I had the same problem and found a pretty simple solution.

The Idea is, that the height: 100% is only applied to the active step.
This can be achieved using following css-rule:

.mat-horizontal-stepper-content[aria-expanded=true] {
    height: 100%;
    display: flex;
    flex-direction: column;
}

I used flex-direction: column, so that the content of <mat-step> can be laid out as a column, without adding an extra container.
I also added a css-class full-height, which I configure in the style.css. That way I can use ViewEncapsulation.

So basically you only need to do the following:

  • <mat-horizontal-stepper> has to be 100% high.
  • .mat-horizontal-content-container has to be 100% high.
  • .mat-horizontal-stepper-content of active step has to be 100% high (.mat-horizontal-stepper-content[aria-expanded=true]).
  • .mat-horizontal-stepper-content of active step has to be 0px high (.mat-horizontal-stepper-content[aria-expanded=false]).

@Springrbua good to know. Thanks!

@Springrbua Thanks for the hint. However, IMHO, the stepper should support this capability natively. Generally speaking (coming from other frameworks), Angular Material should be by far more customizable.

@AGPX I agree, that the stepper should allow you to easily customize the height of th stepper-content.
Usually you want to have the buttons (back and next) always at the same spot and therefore you need a fixed height.

Angular Material should be by far more customizable.
I don't really agree with you on that. Angular Material follows the material design specs and does a great job at that. Of course, a few components could give a little more freedom, but not too much.
If you need more freedom, then you should probably use the CDK, which Angular Material uses under the hood.

Angular Material follows the material design specs...

@Springrbua probably my problem is actually material design, or better the decision to adopt it. My boss tell me "...remove the underline on the input text...", "...put label on the left...", "...change this and that..." and I found very very difficult to apply any cosmetic changes to Material. Probably Angular Material is not the framework tailored for our needs, but it's not my choice (probably it was chosen without a sufficient understanding of its philosophy)... so I have to found workarounds. Forgive me, I'm only a coder. Thanks anyway for the precious support!

@AGPX Take a look at the cdk, maybe it is what you are looking for. Basically all material components are build on top of it and add material design style to it. If you don't need material design style it might be what you are looking for.

@AGPX you should have a more "component-wise" approach.
Of course setting height for the stepper is a very specific change.
But if you want any inputs to have the label on the left, you just create a component which wraps a matInput but never sets the placeholder...Maybe this requires time, but it allows you to create a set based on your project (and always reusable even outside).

Angular Material should be by far more customizable.

Any plan to implement disabled state or it's a no-go feature ?
This is very useful in order to have more dynamic steps without inserting/removing steps dynamically which would be not intuitive for the users.

Thanks a lot.

How can we set success after completion of all state?

@AGPX ok it should work now...
https://stackblitz.com/edit/angular-mat-stepper-full-height

joyo

I want the same. But want stepper fix at the bottom of the page & section should scroll.

Any idea how to achieve that.

@akvaliya if I remember correctly the stepper and the content are flex.
You can swap the order with a simple rule: flex-direction: column-reverse

I'm trying to get the same style requested by @AGPX (horizontal stepper with the steps content cover all the available vertical space), but I'm struggling to get it. Even the workarounds suggested by @tonysamperi and @Springrbua aren't working for me, maybe they worked well when posted, but they don't for sure on version 10.1.3, that I'm using.

Any suggestion?

@kungufli I suggest not using github as stackoverflow.
I think you should create a post there and show what you've tried so far.
I think you should at least create a stackblitz with your environment so that anyone can take a look and maybe help you out!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

theunreal picture theunreal  路  3Comments

julianobrasil picture julianobrasil  路  3Comments

dzrust picture dzrust  路  3Comments

LoganDupont picture LoganDupont  路  3Comments

vanor89 picture vanor89  路  3Comments