在垂直和水平步进材料之间切换

Ash*_*jar 19 angular-material2

如何在角度分量与相同的步进步骤之间切换mat-vertical-steppermat-h​​orizo​​ntal-stepper

dev*_*033 8

从 Angular 12 开始(特别是这些 PR: https: //github.com/angular/components/pull/21940https://github.com/angular/components/pull/22139),您现在可以使用MatStepper(请注意MatHorizontalStepperMatVerticalStepper在这些 PR 中已弃用)并根据需要设置方向输入:

<mat-stepper [orientation]="orientation">
  <mat-step>Step 1</mat-step>
  <mat-step>Step 2</mat-step>
</mat-stepper>
Run Code Online (Sandbox Code Playgroud)

演示版


Joe*_*ugh 7

为了避免重写相同的html内容,请执行以下操作。创建模板,并使用提供参考#hashtag。然后您可以使用来插入它们ng-container *ngTemplateOutlet="hashtag"></ng-container>

这是制作有角度的阶梯式反应性阶梯的示例。

<ng-template #stepOne>
  <div>step one</div>
</ng-template>

<ng-template #stepTwo>
  <div>step two</div>
</ng-template>

<ng-template #stepThree>
  <div>step three</div>
</ng-template>

<ng-template #stepFour>
  <div>step four</div>
</ng-template>

<ng-template [ngIf]="smallScreen" [ngIfElse]="bigScreen">
  <mat-vertical-stepper linear #stepper >
    <mat-step>
      <ng-container *ngTemplateOutlet="stepOne"></ng-container>
    </mat-step>
    <mat-step>
      <ng-container *ngTemplateOutlet="stepTwo"></ng-container>
    </mat-step>
    <mat-step>
      <ng-container *ngTemplateOutlet="stepThree"></ng-container>
    </mat-step>
    <mat-step>
      <ng-container *ngTemplateOutlet="stepFour"></ng-container>
    </mat-step>
  </mat-vertical-stepper>
</ng-template>

<ng-template #bigScreen>
  <mat-horizontal-stepper linear #stepper >
    <mat-step>
      <ng-container *ngTemplateOutlet="stepOne"></ng-container>
    </mat-step>
    <mat-step >
      <ng-container *ngTemplateOutlet="stepTwo"></ng-container>
    </mat-step>
    <mat-step>
      <ng-container *ngTemplateOutlet="stepThree"></ng-container>
    </mat-step>
    <mat-step>
      <ng-container *ngTemplateOutlet="stepFour"></ng-container>
    </mat-step>
  </mat-horizontal-stepper>
</ng-template>
Run Code Online (Sandbox Code Playgroud)

您可以使用角度cdk布局来跟踪屏幕尺寸,如下所示。

import { Component } from '@angular/core';
import {BreakpointObserver, Breakpoints} from '@angular/cdk/layout';

@Component({
  selector: 'app-responsive-stepper',
  templateUrl: './responsive-stepper.component.html',
  styleUrls: ['./responsive-stepper.component.scss']
})
export class ResponsiveStepperComponent implements OnInit {

    smallScreen: boolean;

    constructor(
       private breakpointObserver: BreakpointObserver
      ) {
        breakpointObserver.observe([
          Breakpoints.XSmall,
          Breakpoints.Small
        ]).subscribe(result => {
          this.smallScreen = result.matches;
      });
     }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果您放入 ng-template matStepperNext、matStepLabel 等,则不会工作。所以它不是真正使用的解决方案 (2认同)

Sam*_*hel 5

我将Teradata的Covalent组件与Google的Material组件一起使用。他们使用物料设计,甚至以与Google物料模块相同的方式导入模块。

Covalent的步进器在设置时会考虑模式输入,因此您可以像这样实现HTML模板:

<td-steps [mode]="stepperMode">
  <td-step>
    ...
  </td-step>
  ...
</td-steps>
Run Code Online (Sandbox Code Playgroud)

然后,在组件的打字稿文件中,可以根据需要将变量设置为水平或垂直变量:

if (condition) {
  stepperMode = 'horizontal';
} else {
  stepperMode = 'vertical';
}
Run Code Online (Sandbox Code Playgroud)


Aar*_*ton 5

我想做同样的事情,并最终弄清楚了如何使它工作,并完整地包含了步骤等内容,此外,您还可以在水平和垂直之间同步当前选择的索引,这样就不会改变页面大小将人员重置为步骤1。

这是一个完整的例子。

包装器组件HTML:

<ng-template #horizontal>
  <mat-horizontal-stepper #stepper
    [linear]="isLinear"
    (selectionChange)="selectionChanged($event)">
    <mat-step *ngFor="let step of steps; let i = index"
      [stepControl]="step.form"
      [label]="step.label"
      [optional]="step.isOptional">
      <ng-container *ngTemplateOutlet="step.template"></ng-container>
      <div class="actions">
        <div class="previous">
          <button *ngIf="i > 0" 
            type="button" mat-button
            color="accent"
            (click)="reset()"
            matTooltip="All entries will be cleared">Start Over</button>
          <button *ngIf="i > 0"
            type="button" mat-button
            matStepperPrevious>Previous</button>
        </div>
        <div class="next">
          <button type="button" mat-button
            color="primary"
            matStepperNext
            (click)="step.submit()">{{i === steps.length - 1 ? 'Finish' : 'Next'}}</button>
        </div>
      </div>
    </mat-step>
  </mat-horizontal-stepper>
</ng-template>

<ng-template #vertical>
  <mat-vertical-stepper #stepper
    [linear]="isLinear"
    (selectionChange)="selectionChanged($event)">
    <mat-step *ngFor="let step of steps; let i = index"
      [stepControl]="step.form"
      [label]="step.label"
      [optional]="step.isOptional">
      <ng-container *ngTemplateOutlet="step.template"></ng-container>
      <div class="actions">
        <div class="previous">
          <button *ngIf="i > 0" 
            type="button" mat-button
            color="accent"
            (click)="reset()"
            matTooltip="All entries will be cleared">Start Over</button>
          <button *ngIf="i > 0"
            type="button" mat-button
            matStepperPrevious>Previous</button>
        </div>
        <div class="next">
          <button type="button" mat-button
            color="primary"
            matStepperNext
            (click)="step.submit()">{{i === steps.length - 1 ? 'Finish' : 'Next'}}</button>
        </div>
      </div>
    </mat-step>
  </mat-vertical-stepper>
</ng-template>
Run Code Online (Sandbox Code Playgroud)

包装器组件ts:

import { Component, OnInit, OnDestroy, Input, ContentChildren, QueryList, ViewChild, TemplateRef } from '@angular/core';
import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout';
import { StepComponent } from './step/step.component';
import { Subscription } from 'rxjs';
import { MatStepper } from '@angular/material';

@Component({
  selector: 'stepper',
  templateUrl: './stepper.component.html',
  styleUrls: ['./stepper.component.scss']
})
export class StepperComponent implements OnInit, OnDestroy {

  public selectedIndex: number = 0;
  public isMobile: boolean;
  public template: TemplateRef<any>;
  @Input() isLinear: boolean = true;
  @Input() startAtIndex: number;
  @ContentChildren(StepComponent) private steps: QueryList<StepComponent>;
  @ViewChild('horizontal') templHorizontal: TemplateRef<any>;
  @ViewChild('vertical') templVertical: TemplateRef<any>;
  @ViewChild('stepper') stepper: MatStepper;

  private _bpSub: Subscription;

  constructor(private bpObserver: BreakpointObserver) { }

  ngOnInit() {
    this._bpSub = this.bpObserver
      .observe(['(max-width: 599px)'])
      .subscribe((state: BreakpointState) => {
        this.setMobileStepper(state.matches);
      });

    if (this.startAtIndex) {
      this.selectedIndex = this.startAtIndex;
    }
  }

  selectionChanged(event: any): void {
    this.selectedIndex = event.selectedIndex;
  }

  setMobileStepper(isMobile: boolean): void {
    this.isMobile = isMobile;
    if (isMobile) {
      this.template = this.templVertical;
    }
    else {
      this.template = this.templHorizontal;
    }
    setTimeout(() => {
      // need async call since the ViewChild isn't ready
      // until after this function runs, thus the setTimeout hack
      this.stepper.selectedIndex = this.selectedIndex;
    });
  }

  reset(): void {
    this.stepper.reset();
  }

  ngOnDestroy(): void {
    this._bpSub.unsubscribe();
  }

}
Run Code Online (Sandbox Code Playgroud)

步骤组件HTML:

<ng-template #template>
  <ng-content></ng-content>
</ng-template>
Run Code Online (Sandbox Code Playgroud)

步骤组件ts:

import { Component, Input, Output, TemplateRef, ViewChild, EventEmitter } from '@angular/core';
import { FormGroup } from '@angular/forms';

@Component({
  selector: 'stepper-step',
  templateUrl: './step.component.html',
  styleUrls: ['./step.component.scss']
})
export class StepComponent {

  @Input() isOptional: boolean = false;
  @Input() label: string;
  @Input() form: FormGroup;
  @ViewChild('template') template: TemplateRef<any>;
  @Output() formSubmitted: EventEmitter<any> = new EventEmitter();

  constructor() { }

  submit(): void {
    this.formSubmitted.emit(this.form.value);
  }

}
Run Code Online (Sandbox Code Playgroud)

在组件HTML中使用响应式Angular Material Stepper:

<stepper>
  <stepper-step
    label="Step 1 label"
    [form]="step1form"
    (formSubmitted)="form1Submit($event)">
    content
    <form [formGroup]="frmStep1">
      <mat-form-field>
        <input matInput name="firstname" formControlName="firstname" placeholder="First Name" />
      </mat-form-field>
      content
    </form>
  </stepper-step>
  <stepper-step
    label="Step 2 label"
    [form]="step2form">
    step 2 content
  </stepper-step>
</stepper>
Run Code Online (Sandbox Code Playgroud)

以及表单所需的组件功能:

form1Submit(formValues: any): void {
  console.log(formValues);
}
Run Code Online (Sandbox Code Playgroud)

  • 真的很棒,非常感谢。但是在包装器组件HTML中,您忘记了模板包含:`&lt;ng-container * ngTemplateOutlet =“ template”&gt; &lt;/ ng-container&gt;` (2认同)
  • 我找到了一个方法。在您的StepComponent中,您具有“ @Input()形式:FormGroup;”,应将其更改为两种方式绑定,例如“ formGroupValue:FormGroup;”。@Input()get formGroup(){return this.formGroupValue; } @Output()formGroupChange = new EventEmitter(); 设置formGroup(value){this.formGroupValue = value; this.formGroupChange.emit(this.formGroupValue); }`(https://blog.thoughtram.io/angular/2016/10/13/two-way-data-binding-in-angular-2.html)。在父对象中实例化。做`[(formGroup)] =“ formGroup”`。验证就可以了。 (2认同)

Bil*_*lam 0

您可能想要创建两个单独的步进器并使用 *ngIf 在它们之间切换

<mat-vertical-stepper *ngIf="verticalFlag">
  <mat-step>
  </mat-step>
</mat-vertical-stepper>

<mat-horizontal-stepper *ngIf="!verticalFlag">
  <mat-step>
  </mat-step>
</mat-horizontal-stepper>
Run Code Online (Sandbox Code Playgroud)

  • 但步进器步骤有太多 html 代码,我无法重复。 (4认同)