Components: Stepper (selectionChange) vs (selectionChanged) and [selectedIndex]

Created on 1 Feb 2018  路  20Comments  路  Source: angular/components

Bug, feature request, or proposal:

    <mat-horizontal-stepper [linear]="false" #stepper 
        [selectedIndex]="this.selectedIndex" 
        (selectionChange)="selectionChange($event)">
      <mat-step [completed]="false" label="First">
        <button mat-button (click)="goto(1)">Next</button>
      </mat-step>
      <mat-step [completed]="false" label="Second">
        <button mat-button (click)="goto(0)">Previous (cancelled)</button>
      </mat-step>
    </mat-horizontal-stepper>

In the stepper control the (selectionChange) event cannot be used together with [selectedIndex], because changing the [selectedIndex] also triggers (selectionChange), so there is no way of cancelling the selection programatically, or implement other logic 'before' the change is executed.

Expected it to work as a standard html select control where:

  • when changing the .selectedIndex the (change) event doesn't get automatically triggered
  • the (change) event is triggered 'before' the change is finished, so it can be cancelled with event.preventDefault()

What is the expected behaviour?

  • The current event should be renamed (selectionChanged) = 'after' the step has changed.
  • Emit a new event (selectionChange) = 'before' the step has changed, with option to cancel the action, which doesn't get automatically triggered when selectedIndex changes.

What is the current behavior?

selectionChange = 'after' the step has changed, naming is confusing, gets triggered automatically with [selectedIndex]

What are the steps to reproduce?

screen shot 2018-02-01 at 12 54 07

  1. Select step 2
  2. Press Previous button (the action is cancelled programatically) - ok
  3. Press step 1 header (step 1 is still selected, the action cannot be cancelled, selectedIndex remains on step 2)

StackBlitz: https://stackblitz.com/edit/angular-material2-issue-9lskal

What is the use-case or motivation for changing an existing behavior?

Be able to programatically enable/disable certain steps

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

Material 5.1.0

Is there anything else we should know?

P3 cdstepper needs discussion

Most helpful comment

Is there any progress on the event 'beforeSelectionChanged' ? It would be very usefull

All 20 comments

I think we decided to name our @Output()s across the library as *Change in order to work with 2-way binding syntax. It does seem like probably a bug that this emits when the selectedIndex binding changes though. The events should only be emitted if the user changed the selection

+1

What is the expected behaviour?
The current event should be renamed (selectionChanged) = 'after' the step has changed.
Emit a new event (selectionChange) = 'before' the step has changed, with option to cancel the action, which doesn't get automatically triggered when selectedIndex changes.

We are living in an async world, canceling an action needs to be implemented as a callback. With the above proposal change you would also break existing installations for the selectionChange behaviour.

I would like to propose the following:

Leave the behaviour as it is for simple usage to get notified of a selection change.
Add an option (e.g. [navigation]="'component'", or 'api') to the stepper that all navigation is done by the component. On klick of stepper header or buttons the component receives StepperSelectionEvent and manipulates selectedIndex, directly or by using next() and prev().
Alternatively to an additional option an additional @Output (e.g. beforeSelectionChange) could be used for api usage, to define a component callback and to identify to the stepper that the component takes care of all navigation.

The original post is 6 months old, without any fixes/enhancements proposed. I haven't used material before and need something like a stepper. Does somebody now of a similar stepper library (bootstrap support) ?
Does somebody have a fork fixing this issue?

hey, this is the official doc from stepper? https://material.angular.io/components/stepper/overview i was looking for something like @ouput (selectionChange) there but couldnt find, theres another documentation for mat stepper?

@leonardopaiva You need to look in the CDK docs of the Stepper. https://material.angular.io/cdk/stepper/api

thanks @philip-firstorder

anyone have a workaround for this? I need to disable the change trigger when I set the selectedIndex programatically.

@mmalerba (being assigned for this issue)
@crisbeto (for your recent commits of Stepper)

There is a need for an API for Stepper. The discussion is stalled atm.
I hope you can comment on how to fix or implement such API resulting in an acceptable PR.

Made a change to the CDK stepper source working for 6.4.7 and 7-beta, see diff: stepper.zip

Build with: npm run build

In your project use a npm link in package.json to reference the release build:

"@angular/cdk": "file:../../project/material2/dist/releases/cdk",

Usage:

<mat-vertical-stepper [selectedIndex]="selectedIndex" "(beforeSelectionChange)="beforeSelectionChange($event)">

beforeSelectionChange callback receives the new selectedIndex, set selectedIndex in your Component to change the Step.

The source can be used to create a PR.

@FritzHerbers
Your patch works great. Our project got really stuck due to this issue, your patch helped us to get on track again, thanks.
We hope it gets patched soon, so getting rid of the local cdk clone.

We really need this beforeSelectionChange event as well as we're using a notifications service to inform the user of validation errors (using ngx-toastr). It is easy to show the messages when clicking the 'next' button because we can tap into that event but if the user clicks on the header of the next step (instead of the 'next' button) we have no way of showing the errors.

Has there been any progress on this suggestion? Any active pull request for an implementation? It feels like this suggested functionality would be an appropriate addition to the CDK stepper. Many apps I have worked on benefit from using a stepper-like flow on several screens, but the form dependent validation doesn't really make sense in several of those use cases.

Having hook(s) in place for "before a selection change is completed" in order to back out of the step change and notify the user of any errors would be extremely beneficial.

One specific use case I have run into in the past consists of a stepper containing three steps. The first step is fine working with form validation as we were only collecting information. The second step however does not only collect information, but it takes a portion of that information, and makes an API request to validate some of their input within a 3rd party system before we transition them to the next step. Currently this sort of use case doesn't appear to be fully supported out of the box due to the fact that the step labels could still be clicked to progress to the next step. We were obviously able to stop the transition using the [completed] binding on the step, but providing the user with appropriate feedback proved to be more challenging than maybe was necessary (unless they clicked on a custom button we bound to an action wrapping a call to next()).

In the end we had to abandon using the stepper entirely for the above project and approach it a different way in order for our end users not to have a bit of a confusing experience.

Is this method added in the new angular 7?
As per earlier comment by @FritzHerbers, it was added in beta 7
Made a change to the CDK stepper source working for 6.4.7 and 7-beta

Has there been a pull request opened with the suggested changes posted above?

What is the status for this feature? It's been more then a year.

Is there any progress on the event 'beforeSelectionChanged' ? It would be very usefull

I struggled with this in few days.
Was able to achieve a workaround as setting the stepControl status to pending when every internal form validation all passed.
Then once user clicks on stepper header, I capture the click event to do something and once the job finished, I set the stepControl status to valid and let the stepper moves programmatically by setting new value for selectedIndex

Any solution for before selection change? I am having same requirement

I am looking for a solution too!
Would be even nice to capture the events and handle it the way I like.
That could save me re-implement a lot of code!

Was this page helpful?
0 / 5 - 0 ratings