【问题标题】:Angular Material Stepper causes mat-formfield to validate for dynamic forms when returning to an older stepAngular Material Stepper 导致 mat-form 字段在返回旧步骤时验证动态表单
【发布时间】:2018-12-24 09:23:57
【问题描述】:

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

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

我已经尝试了许多不同的尝试来压制,但我都没有成功。下面是一个基本示例,说明我的第一步如何包含绑定到步骤控件的 hiddenForm、默认表单和在该步骤中创建更多表单的按钮。

我对尝试解决此问题的研究使我相信材料步进器会使所有 mat-form-fields 在无效时变为红色,无论是否新添加。

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

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

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 )

【问题讨论】:

    标签: angular validation dynamic angular-material dynamic-forms


    【解决方案1】:

    背景资料

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

    导致用户体验不佳的场景:

    1. 您完成了第一步,然后进入第二步。进入第二步后,您意识到您在第一步中犯了错误,并决定导航回第一步。您进行了更改,现在再次进行第二步。因为如果您有mat-form-fields,您已经访问了这一步,将添加一个类(可能还有其他更改)并且您的表单字段现在都是红色的。这是一个糟糕的用户体验,因为用户在技术上没有犯任何错误并且可能会过度承受。

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

    修复:

    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>
    

    hero.stepper.ts

    export class heroStepComponent implements OnInit {
      constructor(){
        ...
      }
    
      ngOnInit(){
        ...
      }
    
      stepChanged(event, stepper){
        stepper.selected.interacted = false;
      }
    }
    

    【讨论】:

    • 非常感谢。你让我今天一整天都感觉很好。过去两天我已经解决了这个问题。非常感谢。
    • 没问题,你也打我哈哈
    • 尽管这似乎有效,但它破坏了步进器 next() 函数的功能。 imge.to/i/LRq7F
    • @GeorgeKnap 怎么会这样?我已经将它用于应用程序近一年了,一切都按预期工作。
    • @L1ghtk3ira 说不上为什么。当我实现此功能并使用调用 stepper.next() 的按钮时,内部 selectedIndex 没有改变(请参阅我之前评论中的 gif 链接)。
    【解决方案2】:

    继之前的post 之后,我找到了 stepChanged 函数的更好实现:

      stepChanged(event: StepperSelectionEvent) {
        if (event.previouslySelectedIndex > event.selectedIndex) {
         event.previouslySelectedStep.interacted = false;
        }
      }
    

    此代码将仅在您从前一步骤执行的步骤上设置交互属性。

    【讨论】:

    • 精彩绝伦!几个小时后,发现了这个,真是……太棒了!非常感谢!
    • 对我来说,在当前步骤(而不是上一步)上设置 interacted 就可以了。
    猜你喜欢
    • 2018-04-23
    • 2020-05-18
    • 1970-01-01
    • 2019-04-01
    • 2018-07-14
    • 1970-01-01
    • 2018-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多