139 votes

Puis-je déplacer par programme les étapes d'un mat-horizontal-stepper dans Angular / Angular Material ?

J'ai une question concernant Angular Material (avec Angular 4+). Disons que dans mon modèle de composant, j'ajoute un <mat-horizontal-stepper> et à l'intérieur de chaque étape <mat-step> J'ai des boutons pas à pas pour naviguer dans le composant. Comme ça...

<mat-horizontal-stepper>
  <mat-step>
    Step 1
    <button mat-button matStepperPrevious type="button">Back</button>
    <button mat-button matStepperNext type="button">Next</button>
  </mat-step>
  <mat-step>
    Step 2
    <button mat-button matStepperPrevious type="button">Back</button>
    <button mat-button matStepperNext type="button">Next</button>
  </mat-step>
  <mat-step>
    Step 3
    <button mat-button matStepperPrevious type="button">Back</button>
    <button mat-button matStepperNext type="button">Next</button>
  </mat-step>
</mat-horizontal-stepper>

Maintenant, je me demande s'il est possible de retirer les boutons de chaque étape et de les placer ailleurs dans le système. <mat-horizontal-stepper> dans une position statique ou même en dehors de la <mat-horizontal-stepper> et je peux naviguer vers l'avant et l'arrière en utilisant le code de mon fichier de composants typescript. Pour donner une idée, je voudrais que mon HTML soit quelque chose comme ceci

<mat-horizontal-stepper>
    <mat-step>
        Step 1
    </mat-step>
    <mat-step>
        Step 2
    </mat-step>
    <mat-step>
        Step 3
    </mat-step>
    <!-- one option -->
    <div>
       <button mat-button matStepperPrevious type="button">Back</button>
       <button mat-button matStepperNext type="button">Next</button>
    </div>
</mat-horizontal-stepper>

<!-- second option -->
<div>
   <button (click)="goBack()" type="button">Back</button>
   <button (click)="goForward()" type="button">Next</button>
</div>

264voto

Faisal Points 17084

Oui. Il est possible d'accéder à un pasteur spécifique en utilisant la fonction selectedIndex de l MatStepper . Aussi, MatStepper expose des méthodes publiques next() y previous() . Vous pouvez les utiliser pour vous déplacer d'avant en arrière.

Dans votre modèle :

Ajoutez un identifiant à votre stepper, par ex. #stepper . Ensuite, dans votre goBack() y goForward() transmettent l'identifiant de l'appareil :

<mat-horizontal-stepper #stepper>
    <!-- Steps -->
</mat-horizontal-stepper>    
<!-- second option -->
<div>
   <button (click)="goBack(stepper)" type="button">Back</button>
   <button (click)="goForward(stepper)" type="button">Next</button>
</div>

et dans votre tapuscrit :

import { MatStepper } from '@angular/material/stepper';

goBack(stepper: MatStepper){
    stepper.previous();
}

goForward(stepper: MatStepper){
    stepper.next();
}

Lien vers démo de stackblitz .


Vous pouvez également utiliser ViewChild pour obtenir une référence au composant stepper dans votre TypeScript, comme indiqué ci-dessous :

@ViewChild('stepper') private myStepper: MatStepper;

goBack(){
    this.myStepper.previous();
}

goForward(){
    this.myStepper.next();
}

Dans ce cas, vous ne devez pas passer la référence du stepper dans la méthode dans le html de votre composant. Lien vers Démonstration avec ViewChild


Vous pouvez activer/désactiver le Back y Next en utilisant les moyens suivants :

<button (click)="goBack(stepper)" type="button" 
        [disabled]="stepper.selectedIndex === 0">Back</button>
<button (click)="goForward(stepper)" type="button" 
        [disabled]="stepper.selectedIndex === stepper._steps.length-1">Next</button>

11 votes

Je regardais juste ViewChild et de voir comment je pourrais faire référence au Stepper - mais vous m'avez devancé ! J'adore le fait que vous ayez ajouté la fonctionnalité d'activation et de désactivation ! J'ai quelques points !

0 votes

ViewChild est également une bonne option pour obtenir le stepper. Mais je préférerais passer un id. J'ai également ajouté ViewChild solution dans la démo \o /

0 votes

Bonjour Faisal, merci pour cette excellente réponse, une dernière aide, au lieu de passer un formulaire à la mat-step, pouvons-nous passer des composants angulaires et ensuite, en fonction de la validité de ce composant, puis-je passer à la prochaine mat-step, comment cela peut-il être réalisé, merci.

41voto

Altus Points 1102

En plus de @ Faisal En réponse à la question de l'auteur, voici ma façon de faire sauter le MatStepper sans avoir à passer le stepper dans les arguments.

Ceci est utile lorsque vous avez besoin d'une plus grande flexibilité dans la manipulation du stepper, par exemple à partir d'un fichier Service ou autre chose.

HTML :

<div fxLayout="row" fxLayoutAlign="center center" fxLayoutGap="6px">
  <button (click)="move(0)">1st</button>
  <button (click)="move(1)">2nd</button>
  <button (click)="move(2)">3rd</button>
  <button (click)="move(3)">4th</button>
</div>

Dossier TS :

move(index: number) {
    this.stepper.selectedIndex = index;
}

Voici le démo de stackblitz .

0 votes

Est-il possible d'utiliser mat-horizontal-stepper linear="true" ?

31voto

BlackBeard Points 4608

Si vous vous voulez naviguer de manière programmée à l'étape suivante et si vous êtes en utilisant un pasteur linéaire Suivez les étapes ci-dessous :

  • Créer un stepper comme ça : <mat-horizontal-stepper linear #matHorizontalStepper>

  • Définir mat-step comme ça : <mat-step [completed]="isThisStepDone">

  • De l'intérieur mat-step créer un bouton pour passer à l'étape suivante comme ceci : <button (click)="next(matHorizontalStepper)">NEXT STEP</button>

  • Sur .ts déclare un fichier MatStepper référence nommée pas à pas :
    @ViewChild('matHorizontalStepper') stepper: MatStepper;

  • En outre, dans .ts initialiser le fichier isThisStepDone como faux : isThisStepDone: boolean = false;

  • Ensuite, écrivez une méthode pour PROCHAINE ÉTAPE bouton nommé next() :

     submit(stepper: MatStepper) {
      this.isThisStepDone = true;
      setTimeout(() => {           // or do some API calls/ Async events
       stepper.next();
      }, 1);
     }

NOTE : Le partie asynchrone ( setTimeout() ) est nécessaire en raison de la propagation de l'état via isThisStepDone.

7 votes

La partie asynchrone ( setTimeout() ) est nécessaire en raison de la propagation de l'état via isThisStepDone .

1 votes

Merci monsieur, c'est celui que je cherchais Pour le stepper linéaire.

0 votes

La méthode dans votre code d'exemple n'est pas nommée correctement. Elle devrait être "next" et non "submit".

5voto

Christoph Lütjen Points 772

Si vous êtes à l'intérieur de composants enfants, vous pouvez injecter le stepper.

MyMainPageWithStepper.html (simplified)

<mat-horizontal-stepper>
  <mat-step label="Upload">
    <my-component></my-component>
  </mat-step>
</mat-horizontal-stepper>

MyComponent.ts

constructor(private readonly _stepper: CdkStepper}{}

someFunction(): void {
   this._stepper.next();
}

3voto

M.Laida Points 647

Vous pouvez également le faire en spécifiant l'index réel du stepper en utilisant selectedIndex.

stackblitz : https://stackblitz.com/edit/angular-4rvy2s?file=app%2Fstepper-overview-example.ts

HTML :

<div class="fab-nav-container">
   <mat-vertical-stepper linear="false" #stepper>
       <mat-step *ngFor="let step of stepNodes; let i = index">
           <ng-template matStepLabel>
               <p> {{step.title}} </p>
           </ng-template>
       </mat-step>
   </mat-vertical-stepper>
</div>

<div class="button-container">
   <div class="button-grp">
      <button mat-stroked-button (click)="clickButton(1, stepper)">1</button>
      <button mat-stroked-button (click)="clickButton(2, stepper)">2</button>
      <button mat-stroked-button (click)="clickButton(3, stepper)">3</button>
   </div>
</div>

TS :

import {Component, OnInit, ViewChild} from '@angular/core';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import { MatVerticalStepper } from '@angular/material';
import { MatStepper } from '@angular/material';
export interface INodes {
    title: string;
    seq: number;
    flowId: string;
}
/**
 * @title Stepper overview
 */
@Component({
  selector: 'stepper-overview-example',
  templateUrl: 'stepper-overview-example.html',
  styleUrls: ['stepper-overview-example.scss'],
})
export class StepperOverviewExample implements OnInit {
  @ViewChild(MatVerticalStepper) vert_stepper: MatVerticalStepper;
  @ViewChild('stepper') private myStepper: MatStepper;

  stepNodes: INodes[] = [
    { title: 'Request Submission', seq: 1, flowId: 'xasd12'}, 
    { title: 'Department Approval', seq: 2, flowId: 'erda23'}, 
    { title: 'Requestor Confirmation', seq: 3, flowId: 'fsyq51'}, 
  ];

  ngOnInit() {
  }
  ngAfterViewInit() {
    this.vert_stepper._getIndicatorType = () => 'number';
  }
  clickButton(index: number, stepper: MatStepper) {
      stepper.selectedIndex = index - 1;
  }
}

1 votes

J'utilise juste @ViewChild('stepper') private myStepper: MatStepper; et que this.matStepper.next(); dans ma fonction. Fonctionne parfaitement

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X