当它没有在NgIf中渲染时,在角度4中删除验证

问题描述 投票:3回答:5

我想删除使用NgIf未呈现哪个控件的验证。我试图使用指令删除隐藏控件但不能做同样的,因为它不在模板中呈现。所以我无法在指令中使用ElementRef检查formControlName。这是ts文件

this.form = this._fb.group({
  text1: ['', Validators.required],
  text2:  ['', Validators.required]
});

和模板

<form[formGroup]="form">
  <input type="text" formControlName="text1">
 <div *ngIf="false">
  <input type="text" formControlName="text2">
</div>

我想动态地和全局地删除text2的验证。不删除ts文件中的验证程序。

angular2-template angular-directive angular4-forms angular-validation
5个回答
2
投票

Kara的Angular来源GitHub Issue评论似乎非常相关,并说明了如何通过将反应模型视为“真相来源”并从真实来源创建ngIf表达来解决问题,而不是相反。这表明它是设计的,你必须努力不混淆模板驱动和反应形式的想法。

https://github.com/angular/angular/issues/7970#issuecomment-228624899

感谢您抽出宝贵时间来描述问题。我看了一下你的示例代码,看起来你正在使用被动形式指令(a.k.a“模型驱动”指令:ngFormModel等),而是模板驱动的策略。事实上,ngIf没有从表单的序列化和验证中删除控件实际上是设计的,这就是原因。

在每种形式范例中 - 模板驱动和反应 - 对于活动控件列表只能有一个事实来源。在模板驱动的范例中,真实的来源是模板。在反应等价物中,真实来源是在父组件中创建的表单模型。 DOM没有规定表单的状态。因此,如果您在使用被动方法时从DOM中删除表单控件元素,则表单控件不一定会在事实来源中更改,除非您希望它们。您可以选择通过调用this.form.removeControl('controlName')来强制更新控件,也可以选择将控件保留在表单中。这种灵活性允许您临时添加或删除DOM中的输入,同时保持其表单值序列化(例如,如果表单中有多个可折叠部分,则可以在不影响表单值的情况下删除折叠部分)。我们不希望通过强制模型始终匹配DOM来限制此灵活性并使所有权复杂化。

因此,在您的情况下,如果您选择反应策略,您将需要反转您的逻辑以依赖真实的来源 - 模型。具体来说,这意味着在单击按钮时通过调用this.form.removeControl('name')来强制删除模型中的控件。然后,ngIf应该取决于控件在模型中的存在与* ngIf =“form.contains('name')”,而不是相反。请参见示例plunker:http://plnkr.co/edit/V7bCFLSIEKTuxU9jcp6v?p=preview

值得注意的是,如果您仍在使用beta.14(如在您的plunker中),则需要手动调用this.form.updateValueAndValidity()。在#9097中删除了此要求,因此RC.2之后的版本不需要呼叫。

另一种选择是转换为模板驱动的策略(没有ngFormModel),当从模板中销毁时,它将从表单中删除控件。示例:http://plnkr.co/edit/s9QWy9T8azQoTZKdm7uI?p=preview

我打算关闭这个问题,因为它按预期工作,但我认为我们可以让这次体验变得更加友好。一个好的开始将是文档中的更多烹饪书和指南。


2
投票

更改condition属性后,动态调用该方法以设置和删除验证。例如,

whenConditionChanges(condition:boolean){
  if(!condition){
    this.form.controls["text2"].setValidators([Validators.required]);
    this.form.controls["text2"].updateValueAndValidity();
  } else {
    this.form.controls["text2"].setValidators(null);
    this.form.controls["text2"].updateValueAndValidity();
  }
}

0
投票

因为,你的formcontrol text2取决于某些条件。它不应该是必要的控制。所以你应该反应形式控制

this.form = this._fb.group({
  text1: ['', Validators.required],
  text2:  ['',]
});

如果有场景,您希望确保在dom中出现文本时需要文本,然后在角度中使用自定义验证器。请参阅documentation以了解相同内容。


0
投票

Here示例:在运行时,您可以根据复选框值更新验证器。您可以根据需要设置字段并删除。

http://plnkr.co/edit/YMh0H61LxPGCFtm9Yl13?p=preview


0
投票

我做了什么(并为我工作),使用另一个按钮[禁用]创建一个替代formgroupcontrol,管理按钮和表单的* ngIf。

<mat-step [stepControl]="listBrandFormGroup">
    <form [formGroup]="listBrandFormGroup">
      <ng-template matStepLabel>Define tu marca</ng-template>

      <div class="heading">¡ Haber ! Definamos tu marca</div>
      <div class="subheading">Estamos a punto de hacer magia, solo necesitamos lo siguiente:</div>

      <div class="content" fxLayout="column" fxLayoutGap="8px" *ngIf="listBrand.length > 0">
        <mat-form-field fxFlex="auto">
          <mat-select name="brand_id" formControlName="brand_id" placeholder="Selecciona una marca existente" (selectionChange)="setBrand($event.value);">
            <mat-option [value]="0">Crear una nueva marca</mat-option>
            <mat-option *ngFor="let marca of listBrand" [value]="marca.id">{{marca.display_name}}</mat-option>
          </mat-select>
          <mat-hint>{{descripBrand}}</mat-hint>
        </mat-form-field>
      </div>
    </form>
    <form [formGroup]="brandFormGroup">
      <div class="content" fxLayout="column" fxLayoutGap="8px" *ngIf="idBrand === 0">
        <mat-form-field>
          <mat-label>Marca</mat-label>
          <input matInput formControlName="display_name" required>
          <mat-hint>Ese increíble y único nombre, ¡ tú sabes !</mat-hint>
        </mat-form-field>

        <mat-form-field fxFlex="grow">
          <mat-label>Descripción</mat-label>
          <textarea matInput formControlName="descrip" required></textarea>
          <mat-hint>¿ Cuéntanos de que se trata ?</mat-hint>
        </mat-form-field>

          <mat-label>Logo</mat-label>
          <input type="file" name="photo" ng2FileSelect required formControlName="display_logo" />
      </div>

      <div class="actions" fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="8px">
        <button mat-button type="button" (click)="stepper.reset()" [disabled]="brandFormGroup.pristine"
                color="primary">RESET
        </button>
        <button mat-raised-button matStepperNext color="primary"  [disabled]="brandFormGroup.invalid" *ngIf="idBrand === 0">SIGUIENTE</button>
        <button mat-raised-button matStepperNext color="primary"  [disabled]="listBrandFormGroup.invalid" *ngIf="idBrand > 0">SIGUIENTE</button>
        <button mat-raised-button matStepperNext color="primary"  [disabled]="listBrandFormGroup.invalid" *ngIf="idBrand > 0" (click)="launch();"><i class="material-icons">launch</i>LANCÉMONOS</button>
      </div>
    </form>
  </mat-step>
© www.soinside.com 2019 - 2024. All rights reserved.