Angular 2 - 使用带有可选字段的 ngControl
Posted
技术标签:
【中文标题】Angular 2 - 使用带有可选字段的 ngControl【英文标题】:Angular 2 - using ngControl with optional fields 【发布时间】:2016-06-14 05:19:03 【问题描述】:我很难在表单中同时使用 *ngIf 和 ngFormModel 来验证所述表单。
用例是这样的:根据用户输入,隐藏或停用表单中的某些特定字段。但如果显示这些输入,则必须对其进行验证。
当只需要基本验证时,我可以采取一种或另一种方式:
如果只需要输入,则使用ngControl
和required
可以正常工作
如果需要特定格式,可以使用pattern
属性。它不是 Angular,但它可以工作。
但是为了实现更复杂的验证,我一直在尝试使用ngControl
耦合到ngFormModel
以便使用自定义检查。我使用了以下页面上的代码:
How to add form validation pattern in angular2(以及那里引用的链接)
Angular2 Forms :Validations, ngControl, ngModel etc
我的代码如下:
HTML
<div>
<h1>Rundown of the problem</h1>
<form (ngSubmit)="submitForm()" #formState="ngForm" [ngFormModel]="myForm">
<div class="checkbox">
<label>
<input type="checkbox" [(ngModel)]="model.hideField" ngControl="hideField"> Is the input below useless for you ?
</label>
</div>
<div *ngIf="!model.hideField">
<div class="form-group">
<label for="optionalField">Potentially irrelevant field </label>
<input type="text" class="form-control" [(ngModel)]="model.optionalField" ngControl="optionalField" required #optionalField="ngForm">
<div [hidden]="optionalField.valid || optionalField.pristine" class="alert alert-warning">
This input must go through myCustomValidator(), so behave.
</div>
</div>
</div>
<button type="submit" class="btn btn-primary" [disabled]="!formState.form.valid">I can't be enabled without accessing the input :(</button>
<button type="submit" class="btn btn-default">Submit without using form.valid (boo !)</button>
</form>
</div>
打字稿
import Component, ChangeDetectorRef, AfterViewInit from 'angular2/core';
import NgForm, FormBuilder, Validators, ControlGroup, FORM_DIRECTIVES from 'angular2/common';
@Component(
selector: 'accueil',
templateUrl: 'app/accueil.component.bak.html',
directives:[FORM_DIRECTIVES],
providers: [FormBuilder]
)
export class AccueilComponent implements AfterViewInit
private myForm: ControlGroup;
model: any;
constructor(fb: FormBuilder, cdr: ChangeDetectorRef)
this.cdr = cdr ;
this.model = ;
this.myForm = fb.group(
"hideField": [false],
"optionalField": [this.model.optionalField, Validators.compose([this.myCustomValidator])]
);
ngAfterViewInit()
// Without this, I get the "Expression has changed after it was checked" exception.
// See also : https://***.com/questions/34364880/expression-has-changed-after-it-was-checked
this.cdr.detectChanges();
submitForm()
alert("Submitted !");
myCustomValidator(optionalField)
// Replace "true" by "_someService.someCheckRequiringLogicOrData()"
if(true)
return null;
return "ohNoes": true ;
即使使用 *ngIf 从模板中删除了输入,构造函数仍然在引用控件。这反过来又阻止了我使用 [disabled]="!formState.form.valid",因为 myForm
可以理解为无效。
我的目标是使用 Angular 2 吗?我确信这不是一个不常见的用例,但是以我目前的知识,我不知道如何使它工作。
谢谢!
【问题讨论】:
现在遇到同样的问题,用户表单密码在编辑时是可选的。 【参考方案1】:您可以尝试重置控件上的验证器。这意味着,当您希望由于状态更改而将一组新的验证器绑定到控件时,您将重新定义验证器函数。
在您的情况下,当您的复选框被选中/取消选中时,您希望发生以下情况:
-
将输入设置为可选(非必需),但仍根据您的自定义验证器进行验证。
当复选框未选中时,将控件的验证器恢复到其原始状态。
再次验证控件,以便更新
form.valid
。
See my plnkr sample based on Angular.io's Forms Guide
if (optional)
this.heroFormModel.controls['name'].validator = Validators.minLength(3);
else
this.heroFormModel.controls['name'].validator =
Validators.compose([Validators.minLength(3), Validators.required]);
this.heroFormModel.controls['name'].updateValueAndValidity();
【讨论】:
这确实很好用。感谢您为我解决问题,并提供启动解决方案。我天真地认为可以有类似“始终定义控件,但只有在匹配控件位于(阴影)dom 中时才应用它们”之类的东西,但我想这并不容易。原因是:条件并不总是像复选框那么简单。但即使它基于其他一些输入,也可以以类似的方式使用(输入)或(更改),所以它很好,真的。再次感谢!【参考方案2】:我刚刚遇到了完全相同的问题,并找到了一个依赖于手动包含和排除控件的解决方法:
import Directive, Host, SkipSelf, OnDestroy, Input, OnInit from 'angular2/core';
import ControlContainer from 'angular2/common';
@Directive(
selector: '[ngControl]'
)
export class MyControl implements OnInit, OnDestroy
@Input() ngControl:string;
constructor(@Host() @SkipSelf() private _parent:ControlContainer)
ngOnInit():void
// see https://github.com/angular/angular/issues/6005
setTimeout(() => this.formDirective.form.include(this.ngControl));
ngOnDestroy():void
this.formDirective.form.exclude(this.ngControl);
get formDirective():any
return this._parent.formDirective;
为了完成这项工作,必须首先从表单中排除所有动态控件;详情请见plunkr。
【讨论】:
【参考方案3】:这是 RC4 的更新版本。为了我的目的,我还将它重命名为 npControl。
import Directive, Host, OnDestroy, Input, OnInit from '@angular/core';
import ControlContainer from '@angular/forms';
@Directive(
selector: '[npControl]'
)
export class NPControlDirective implements OnInit, OnDestroy
@Input() npControl: string;
constructor(@Host() private _parent: ControlContainer
)
ngOnInit(): void
console.log('include ', this.npControl);
setTimeout(() => this.formDirective.form.include(this.npControl));
ngOnDestroy(): void
console.log('exclude ', this.npControl);
this.formDirective.form.exclude(this.npControl);
get formDirective(): any
return this._parent;
【讨论】:
以上是关于Angular 2 - 使用带有可选字段的 ngControl的主要内容,如果未能解决你的问题,请参考以下文章
Angular 复习与进阶系列 – Angular Compiler (AKA ngc)
运行 ng serve 时找不到模块“@angular/compiler-cli/ngc”
如何在带有 defaultValue 的可选字段上使用 jQuery Validator 自定义方法?