Могу ли я программно перемещать шаги mat-horizontal-stepper в Angular / Angular Material

88

У меня вопрос по Angular Material (с Angular 4+). Скажем, в моем шаблоне компонента я добавляю <mat-horizontal-stepper>компонент, и на каждом шаге у <mat-step>меня есть пошаговые кнопки для навигации по компоненту. Вот так...

<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>

Теперь мне интересно, можно ли удалить кнопки с каждого шага и разместить их в другом месте <mat-horizontal-stepper>в статической позиции или даже за пределами, <mat-horizontal-stepper>и я могу перемещаться назад и вперед, используя код в моем файле машинописного текста компонента. Чтобы дать представление, я хотел бы, чтобы мой HTML был примерно таким

<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>
Майк Сав
источник

Ответы:

182

Да. Можно перейти к конкретному шаговому двигателю, используя selectedIndexсвойство MatStepper. Кроме того, MatStepperпредоставляет публичные методы next()и previous(). Вы можете использовать их для перемещения вперед и назад.

В вашем шаблоне:

Добавьте идентификатор в свой шаговый двигатель, например #stepper. Тогда в ваших goBack()и goForward()методах, передать шаговый идентификатор:

<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>

.. и в вашем машинописном тексте:

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

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

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

Ссылка на демонстрацию stackblitz .


Вы также можете использовать его ViewChildдля получения ссылки на шаговый компонент в вашем TypeScript, как показано ниже:

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

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

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

В этом случае вам не нужно передавать ссылку на шаговый двигатель в методе в html вашего компонента. Ссылка на демонстрацию с ViewChild


Вы можете включить / отключить Backи Nextкнопки с помощью следующих действий :

<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>
Фейсал
источник
8
Я просто смотрел ViewChildи видел, как я могу сослаться на Степпер - но вы меня опередили! Мне нравится тот факт, что вы также добавили функцию отключения / включения! Есть несколько очков!
Майк Сэв
ViewChildтакже хороший вариант приобрести степпер. Но я бы предпочел передать идентификатор. Я также добавил ViewChildрешение в демо \ o /
Фейсал
Привет, Фейсал, спасибо за такой отличный ответ, еще одна помощь, вместо передачи формы в mat-step, можем ли мы передать угловые компоненты, а затем, в зависимости от того, является ли этот компонент действительным, могу ли я перейти к следующему mat-step, как этого можно достичь , thankyou
Enthu
Хорошее решение. Но как мы могли ограничить область прокрутки только содержимым степпера, а не фактическим заголовком. Если вы добавите кучу контента, то заголовок скроет из виду. Поскольку заголовок указывает на то, где находится пользователь в каком-либо процессе, важно, чтобы заголовок был виден независимо от количества контента на каждом этапе.
Уэйн Ристерер 08
1
Если вы используете Angular 8 и @ViewChild, вы должны использовать static: false. Для @ViewChild('stepper', {static: false}) private myStepper: MatStepper; Angular это значение по умолчанию будет false в ссылке
rorvis
29

В дополнение к @ Faisal ответу , это мой подход к тому, чтобы заставить MatStepper прыгать без необходимости передавать степпер в аргументах.

Это полезно, когда вам нужно больше гибкости в управлении шаговым двигателем, например, от a Serviceили чего-то еще.

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>

Файл TS:

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

Вот демонстрация stackblitz .

Altus
источник
21

Если вы хотите программно перейти к следующему шагу и если вы используете линейный шаговый двигатель , выполните следующие шаги:

  • Создайте stepperвот так: <mat-horizontal-stepper linear #matHorizontalStepper>
  • Определите mat-stepтак:<mat-step [completed]="isThisStepDone">
  • Изнутри mat-step создайте кнопку, чтобы перейти к следующему шагу, например: <button (click)="next(matHorizontalStepper)">NEXT STEP</button>
  • В .tsфайле объявите MatStepperссылку с именем stepper :
    @ViewChild('matHorizontalStepper') stepper: MatStepper;
  • Кроме того, в .tsфайле инициализируйте isThisStepDoneкак false :isThisStepDone: boolean = false;
  • Затем напишите метод для кнопки СЛЕДУЮЩИЙ ШАГ с именем next():

    submit(stepper: MatStepper) {
     this.isThisStepDone = true;
     setTimeout(() => {           // or do some API calls/ Async events
      stepper.next();
     }, 1);
    }
    
Черная борода
источник
3
Асинхронная часть ( setTimeout()) требуется из-за распространения состояния через isThisStepDone.
Юрий
2

Вы также можете сделать это, указав фактический индекс шагового двигателя с помощью 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
Я просто использую @ViewChild('stepper') private myStepper: MatStepper;и this.matStepper.next();в своей функции. Работает отлично
Макс