返回较旧的步骤时,Angular Material Stepper使Mat-formfield验证动态形式

L1g*_*ira 5 validation dynamic dynamic-forms angular-material angular

mat-stepper使用动态模板时,角材出现问题。例如,我有一个具有3个步骤的步进器,每个步骤都有自己的形式。但是,第一步使用隐藏表单来确定它是否有效,因为此步骤可以动态添加更多表单,因此将所有表单绑定到该步骤是不可能的。

第一步时,您可以创建多个表单,并且一切都会按预期进行,而不会对添加的新表单进行任何随机验证。如果您转到步骤2或3,然后回到第一步,然后创建一个新表单,它将自动以所有突出显示为红色的字段开始,就会出现问题。

我尝试了多种尝试来压制,但是我没有成功。下面是一个基本示例,说明我的第一步如何包含与步骤控件绑定的hiddenForm,默认表单以及在该步骤中创建更多表单的按钮。

我试图解决此问题的研究使我相信,无论是否新添加,材料步进器都会使所有垫形场变为红色(如果无效)。

<mat-horizontal-stepper [linear]="true">
    <mat-step [stepControl]="hiddenForm" label="step 1"
      <form [formGroup]="myForm">
        <mat-form-field>
          <mat-label>
            First Name
          </mat-label>

          <input [formControl]="firstName"matInput>

          <mat-error *ngIf="!firstName.valid && firstName.touched">
            First Name required
          </mat-error>
        </mat-form-field>
      </form>

    <button (click)="AddNewForm()">Add New Form</button>
  </mat-step>
</mat-horizontal-stepper>
Run Code Online (Sandbox Code Playgroud)

尝试失败的尝试:(当前表单是新添加的表单)

this.currentForm.markAsUntouched();
this.currentForm.markAsPristine();
this.currentForm.setErrors(null);
this.currentForm.reset();

this.currentForm.get('firstName).setErrors(null);
this.currentForm.get('firstName).reset();
this.currentForm.get('firstName).markAsPristine();
this.currentForm.get('firstName).markAsUntouched();

<mat-step [completed]="true" ..> ( on all steps )
Run Code Online (Sandbox Code Playgroud)

L1g*_*ira 9

背景资料

我发现最好的解决方案是更改上的参数mat-stepper。在任何给定时间都会选择一个步骤。在步骤中,您可以更改步骤是否已交互。如果先前已访问过某个步骤,则该interacted参数将设置为true。这样做是有意的,但是会给所有类添加一个类,mat-form-fields导致它们变红。

这是导致不良用户体验的方案:

  1. 您完成第一步,然后转到第二步。转到第二步后,您意识到您在第一步中犯了一个错误,并决定导航回第一步。您进行了更改,然后再次进行第二步。因为您已经访问过此步骤,所以如果您有mat-form-fields一个班级(可能会进行其他更改),那么您的表单字段将全部变为红色。这是糟糕的用户体验,因为从技术上讲,用户没有犯任何错误,并且可能会过度负担。

  2. 在第一步中,您将在其中创建动态表单。为了简单起见,让我们使用英雄之旅类比。在第一步中,您可以动态添加表单。每个表格代表您要添加的新英雄。您已经添加了3个英雄,然后继续执行第2步。在完成第2步之前,您意识到您已经忘记了几个英雄,然后返回到第1步。现在,当您单击“创建英雄”按钮时,会弹出动态表单,但是mat-form-fields现在所有红色,就像用户犯了一个错误。这是另一个糟糕的用户体验。

解决方法:

hero.stepper.html

<mat-horizontal-stepper [linear]="true" 
  (selectionChange)="stepChanged($event, stepper);">

  <mat-step [stepControl]="hiddenForm" label="step 1"
    <form [formGroup]="heroFormGroupArray[0]">
      <mat-form-field>
        <mat-label>Hero Name</mat-label>

        <input [formControl]="heroName"matInput>

        ...
      </mat-form-field>
    </form>

    <button (click)="AddNewHero()">Add New Hero</button>
  </mat-step>
</mat-horizontal-stepper>
Run Code Online (Sandbox Code Playgroud)

英雄步进

export class heroStepComponent implements OnInit {
  constructor(){
    ...
  }

  ngOnInit(){
    ...
  }

  stepChanged(event, stepper){
    stepper.selected.interacted = false;
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 尽管这似乎有效,但它破坏了步进器的“next()”函数的功能。https://imge.to/i/LRq7F (2认同)

Geo*_*nap 7

继上一篇文章后,我发现了 stepChanged 函数的更好实现:

  stepChanged(event: StepperSelectionEvent) {
    if (event.previouslySelectedIndex > event.selectedIndex) {
     event.previouslySelectedStep.interacted = false;
    }
  }
Run Code Online (Sandbox Code Playgroud)

此代码将仅在您从前面的步骤转到的步骤上设置交互属性。