この記事では、Angular におけるレスポンシブフォームについて説明し、サンプルを交えて簡単なフォームの実装方法を紹介します。
先日会社のフレームワークのバージョンアップに伴い、フォームを手作業でチェックするという従来の方式を廃止し、全てのフォームをレスポンシブ対応に変更しました。最初は使ったことがないのは私だけかと思っていましたが、グループの他のメンバーと知り合ってみると、基本的にはあまり慣れていないことがわかりました。今後は時間も限られているので仕方ありません。 「やりながら学んで変化していくものなので、落とし穴を踏んでしまうのは仕方のないことです。もちろん、私も勉強に時間を費やしました。慣れている人にとってはとても簡単かもしれませんが、それでも一種の種類です」学習プロセスと概要、および問題を解決する方法を要約するための洗練の。ここでは、公式ドキュメントのように API の紹介をやみくもに書くのではなく、理論と実際のビジネス ニーズを組み合わせることが重要です。
なぜ主にレスポンシブフォームを導入するのでしょうか?リアクティブ フォームは、基礎となる
Form Object Modelへの直接的かつ明示的なアクセスを提供するためです。これらはテンプレート駆動型のフォームよりも堅牢であり、拡張性、再利用性、テスト性が優れています。より複雑なフォームに適していますが、実際、最も重要なことは、他のことを行う方法がわからないことです。 [関連チュートリアルの推奨事項: "angular チュートリアル"]1. レスポンシブ フォームの基本概念
1.FormControl、FormArray、FormGroup1.
FormControl: フィールド バインディングなどの単一フォーム コントロールの値と検証ステータスを追跡するために使用されます//初始化一个栏位的值为测试名字,并且不可用
const Name:FormControl = new FormControl({value:'测试名字', disabled: true });
: フォーム コントロール配列の値とステータスを追跡するために使用されます (複数のフィールドの集合、よく使用されるテーブル、フォーム内の埋め込みテーブルなど)//定义表单对象的属性为aliases的FormArray
this.validateForm = this.fb.group({aliases: this.fb.array([]),});
//获取FormArray
get aliases() {return this.validateForm.get('aliases') as FormArray;}
//给FormArray 添加item
this.aliases.push(
this.fb.group({Id: 0,Name: [null],})
);
: used 単一のフォーム コントロールの値と検証ステータスを追跡するために、単一または複数の FormControl および FormArray を含めることができます。通常、フォームは FormGroup インスタンスに対応し、フォームの各フィールドは FormControl および FormArray に対応します。 FormArray FormGroups など、相互に入れ子にすることができるため、非常に柔軟です。 validateForm = new FormGroup({Name: new FormControl({value:'测试名字', disabled: true }),});
validateForm = this.fb.group({});
: これは注入可能なサービス プロバイダーです。複数のフォーム コントロール インスタンスを手動で作成するのは非常に面倒です。FormBuilder サービスには、フォーム コントロールを生成する便利なメソッドがいくつか用意されています。以前の各作成最初に FormGroup を生成し、次に FormControl を生成する必要がありますが、FormBuilder のグループ メソッドを使用すると、繰り返しコードを減らすことができます。端的に言えば、フォームを簡単に生成するのに役立ちますvalidateForm!: FormGroup;
//手动创建
validateForm = new FormGroup({
Name: new FormControl('测试名字'),
});
//FormBuilder表单构建器
validateForm = this.fb.group({
Name:[ { value:'测试名字',disabled:true}],
});
2。検証
フォーム検証は、ユーザー入力が完全で正しいことを確認するために使用されます。単一のバリデーターをフォーム コントロールに追加する方法とフォーム全体のステータスを表示する方法 通常、バリデーターはすべての検証が合格したことを示す null を返します。
1.
同期バリデーター: 同期バリデーター関数は、コントロール インスタンスを受け入れ、一連の検証エラーまたは null を返します。これは、FormControl をインスタンス化するときに渡すことができます。 2 番目のパラメーターとして渡します <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;"> //formControlName的值必须和ts代码中FormControl 的实例一致
<input type="text" id="name" class="form-control" formControlName="name" required>
//判断对应的FormControl 是否没通过校验 而有错误信息
<div *ngIf="name.errors?.[&#39;required&#39;]">
Name is required.
</div></pre><div class="contentsignin">ログイン後にコピー</div></div><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">//初始化一个栏位并且加入必填校验验证器
const name:FormControl = new FormControl({&#39;测试名字&#39;, disabled: true },Validators.required,);
//获取这个FormControl
get name() { return this.heroForm.get(&#39;name&#39;); }</pre><div class="contentsignin">ログイン後にコピー</div></div>
2.
: 非同期関数はコントロール インスタンスを受け入れ、Promise または Observable を返します。すべての同期バリデーターが渡された後でのみ、Angular の非同期バリデーターが使用されます。 FormControl をインスタンス化するときに、それを 3 番目のパラメーターとして渡すことができます3.
組み込みバリデーター: たとえば、一部の長さを検証するには、空にすることはできません。 4.
カスタム バリデーター を実装するために Validator クラスが提供されています: システム内で提供されるバリデーターは既存のニーズを満たすことができません。カスタム バリデーターを使用して、いくつかのパーソナライズされた処理を行うことができます検証のために、カスタム バリデーターは ValidationErrors タイプまたは空を返す必要があります //formControlName的值必须和ts代码中FormControl 的实例一致
<input type="text" id="name" class="form-control" formControlName="name" required>
//判断对应的FormControl 是否没通过校验 而有错误信息
<div *ngIf="name.hasError('Invalid')">
名字也太长了吧....
</div>
//初始化一个栏位并且加入必填校验验证器
const name:FormControl = new FormControl({'测试名字', disabled: true },this.CustomValidators());
CustomValidators() {
return (control: AbstractControl): ValidationErrors | null => {
if(control.value.length!=10)
{
return {Invalid:true}
}
return null;
};
}
3. フォームと要素の基本的なメソッドと属性 1. 简单的表单实现 ###### 我们主要用到的框架版本是Angular 12 + NG-ZORRO, 所以在下面很多实现和示例代码将与他们有关,虽然可能代码不一样,但也只是在UI层面的区别稍微大一点点,但对于TS代码,只是换汤不换药,稍微注意一下就好了,其实下面实例中的需求,基本就是我在工作时需要做的的一些基本内容和遇到的问题,经过查阅资料后解决的思路和过程,甚至截图都一模一样。 实现最基本的表单新增功能并且校验员工ID为必填以及长度不能超过50,要实现的效果图如下 1.首先需求未提出有特殊注意点,基本都是简单的输入框赋值然后保存,只要基本的概念搞清楚实现这种最简单 2.我们用一个FormGroup和6个FormControl 完成和界面绑定即可 3.绑定验证器用于校验长度和必填 1.定义html 表单结构 2.在TypeScript代码中声明表单对象,在构造函数中注入FormBuilder,并且在ngOnInit中进行表单初始化 2.在表格中应用表单 需要实现表格的表单新增和提交以及个性化定制需求,要实现的效果图和需求描述如下 1.点击Add 添加一行表格 ,编辑完毕,点击Save保存数据,点击Revoke取消编辑 2.默认开始时间和结束时间禁止使用 3.当选择Contract Type为 “短期合同” Contract start date 和Contract end date可用,当选择Contract Type为 “长期合同”不可用 4.如果Contract start date 和Contract end date可用,需要验证开始结束时间合法性,例如开始事件不能超过结束时间 1.在表格中使用表单,虽然表单在表格中,但是他的每一列同样都是一个个FormControl 2.一共4列需要输入值,就说明有4个FormControl 然后最后一列就是2个按钮 3.我们根据上面的基础知识知道,FormControl 不能单独使用,所以需要被FormGroup包裹,此时说明一行对应一个FormGroup 4.由一行对应一个FormGroup知道,我们的表格时多行的,也就是有多个FormGroup,我们可以使用FormArray来存储,因为他代表一组表单组 5.根据需求第2点默认开始时间和结束时间禁止使用,我们知道在一开始初始化时,设置开始结束时间对应的FormControl 为disabled就行了 6.第3点需求需要涉及联动,也就是当Contract Type对应的FormControl 的值为“短期合同”时,需要将 “开始结束时间”对应的FormControl设置为可用,这个需要自定义验证器来完成 1.首先定义Html表单结构 2.在TypeScript代码中声明表单对象validateForm,然后初始化一个FormArray类型的属性aliases的实例作为表格formArrayName的值 3.点击Add按钮时向表单对象validateForm的属性aliases添加一条数据 4.定义Contract Type 联动的自定义校验器 contractTypeValidation()方法 5.定义时间校验器 timeValidation()方法,如果时间不合法,将FormControl的错误状态设置属性beginGtendDate,然后在模板中根据这个属性来选择是否渲染日式信息 更多编程相关知识,请访问:编程入门!! 以上がAngular のレスポンシブ フォームの簡単な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。##メソッド
効果を使用 setValue() patchValue()setVlue を使用すると、FormControl コントロールの値を設定できますが、これを使用する場合は、FormGroup のすべてのプロパティを設定する必要があります。負荷割り当ての変更によく使用される単一の割り当てはできません。 reset ()patchValue を使用すると、FormControl の値を設定することもできます。設定せずに、必要に応じて指定した FormControl を設定できます。通常、フィールド値の更新に使用されます。 FormControl は、現在のコントロールのすべての状態をリセットするために使用されます。これは、FormGroup でリセットするために使用されます。フォーム オブジェクト内のコンテンツ、たとえば、コントロールが無効に設定されている場合、control.reset({ value: 'Drew',disabled: true }); #markAsPristine() は、フォーム コントロールの値を未変更としてマークします。このメソッドは主にフォームがリセットされるときに使用されます。このとき、そのステータス pristine は true ##markAsDirty() は、フォーム FormControl コントロール値を変更済みとしてマークします。この時点で、そのステータス Dirty は true updateValueAndValidity( ) FormControl コントロールなどの値と検証ステータスを再計算します。 # フォームへ FormControl コントロールはバリデーターを設定します。複数のバリデーターを設定する場合は、配列 "setValidators() setValidators([v1,v2,v3]) "# を使用します。 disable() FormControl コントロールを使用できないように設定します。FormControl が無効になると、フォームの通常の値の対応する値が getValue() になることに注意してください。 getRawValue() を使用して元の値オブジェクトを取得し、対応する FormControl の値を取得できます。 ##FormControl コントロールを有効にする 属性 ##属性使用法の説明
FormControl コントロールのタッチされた値が true の場合、コントロールがフォーカスを取得したことを意味し、その逆も同様です。 #untouched が true の場合、コントロールがフォーカスを取得していないことを意味し、その逆も同様です
touched フォーム要素がフォーカスされていないことを示します。純粋であり、ユーザーによって操作されていません。markAsPristine メソッドを使用して true に設定できますpristine #dirty フォームが要素はユーザーによって操作されました。markAsDirty メソッドを使用して true に設定できます。 status フォームのステータスを取得しますFormControl コントロール ##Errors#現在のコントロールのエラー情報を取得 # # 二.实例分析及应用
需求1
分析
实现步骤
<!-- formGroup 属性绑定表单对象 -->
<form nz-form [formGroup]="validateForm" nzLayout="vertical">
<nz-form-label nzRequired>Employee ID
</nz-form-label>
<!-- Employee_ErrorTrip为验证不通过弹出的提示信息 -->
<!-- formControlName绑定表单元素FormControl -->
<nz-form-control [nzErrorTip]="Employee_ErrorTrip">
<input nz-input formControlName="EmployeeID" placeholder="" />
</nz-form-control>
<ng-template #Employee_ErrorTrip let-control>
<ng-container *ngIf="control.hasError('required')">
员工编号为必填项目
</ng-container>
</ng-template>
</form>
//定义表单对象
validateForm:FormGroup;
//构造函数注入FormBuilder
constructor(private fb: FormBuilder){}
//在声明周期钩子函数中初始化表单
ngOnInit() {
//初始化并且绑定必填验证器和长度验证器
this.validateForm = this.fb.group({
EmployeeID: ['', [Validators.required, Validators.maxLength(50)]],
})
}
需求2
分析
实现步骤
<nz-table [nzData]="CONTRACTS" nzTableLayout="fixed" [nzShowQuickJumper]="true">
<thead>
<tr>
<th>Contract type</th>
<th>Contract start date</th>
<th>Contract end date</th>
<th>Agreement item</th>
<th>Operation</th>
</tr>
</thead>
<tbody>
<!-- 绑定表单组属性aliases -->
<ng-container formArrayName="aliases">
<!-- 将表单组中当前行的索引与formGroup绑定 -->
<tr [formGroupName]="i" *ngFor="let data of aliases.controls;index as i">
<td>
<nz-form-item>
<nz-form-control nzSpan="1-24">
<!-- AccountName绑定FormControl -->
<nz-select nzShowSearch nzAllowClear nzPlaceHolder="" formControlName="Type">
<nz-option *ngFor="let option of Type" [nzValue]="option.Code" [nzLabel]="option.Value">
</nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control nzSpan="1-24" [nzErrorTip]="StartDate">
<nz-date-picker id="StartDate" formControlName="StartDate" nzPlaceHolder="">
</nz-date-picker>
<!-- 校验提示模板用于时间验证器 -->
<ng-template #StartDate let-control>
<!-- 判断时间验证器是否存在beginGtendDate属性,如果有说明没有通过验证 然后展示提示信息 -->
<ng-container *ngIf="control.hasError('beginGtendDate')">
开始时间不能晚于结束时间
</ng-container>
</ng-template>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control nzSpan="1-24" [nzErrorTip]="EndDate">
<nz-date-picker style="width: 100%;" formControlName="EndDate" nzPlaceHolder="">
</nz-date-picker>
<ng-template #EndDate let-control>
<ng-container *ngIf="control.hasError('beginGtendDate')">
开始时间不能晚于结束时间
</ng-container>
</ng-template>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control nzSpan="1-24">
<nz-select nzShowSearch nzAllowClear nzPlaceHolder="" formControlName="ContractType">
<nz-option *ngFor="let option of ContractTypes" [nzValue]="option.Code" [nzLabel]="option.Value">
</nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
</td>
<td>
<button style="color: #009688;" nz-button nzType="text">
<i nz-icon nzType="save"></i>Save
</button>
<button nz-button nzType="text" nzDanger>
<i nz-icon nzType="redo"></i>Revoke
</button>
</td>
</tr>
</ng-container>
</tbody>
</nz-table>
//定义表单对象
validateForm:FormGroup;
//构造函数注入FormBuilder
constructor(private fb: FormBuilder){}
//在声明周期钩子函数中初始化一个表单对象validateForm
ngOnInit() {
this.validateForm = this.fb.group({
aliases: this.fb.array([]),
});
}
//声明aliases属性用作界面formArrayName绑定
get aliases(){
return this.validateForm.get('aliases') as FormArray;
}
addNewRow() {
const group = this.fb.group({
//添加给Type初始化验证器
Type: [null, [CommonValidators.required, this.contractTypeValidation()]],
//初始化禁用StartDate和EndDate的FormControl
StartDate: [{ value: null, disabled: true }, []],
EndDate: [{ value: null, disabled: true },[]],
ContractType: [null, [CommonValidators.required, CommonValidators.maxLength(20)]],
})
this.aliases.push(group);
}
//自定义Contract Type验证器
contractTypeValidation() {
return (control: AbstractControl): ValidationErrors | null => {
let contents: any[] = this.validateForm.value.aliases;
if (control.touched && !control.pristine) {
//获取表单组
const formArray: any = this.validateForm.controls.aliases;
//找到正在编辑的行的索引
const index = contents.findIndex((x) => !x.isShowEdit);
//获取开始结束时间FormControl 实例
const StartDate: AbstractControl =
formArray.controls[index].get('StartDate'),
EndDate: AbstractControl = formArray.controls[index].get('EndDate');
if (control.value === "短期合同") {
//给开始结束时间设置验证器用于验证时间合法性
StartDate.setValidators([CommonValidators.required, this.timeValidation()]);
EndDate.setValidators([this.timeValidation()]);
//启动开始结束时间控件
EndDate.enable();
StartDate.enable();
} else {
//Contract Type不是短期合同就清除验证器
StartDate.clearValidators();
EndDate.clearValidators();
//禁用开始结束时间
EndDate.disable();
StartDate.disable();
}
}
return null;
}
}
//自定义时间验证器
timeValidation()
{
return (control: AbstractControl): ValidationErrors | null => {
if (!control.pristine) {
let contents: any[] = this.validateForm.value.aliases;
const formArray: any = this.validateForm.controls.aliases;
const index = contents.findIndex((x) => !x.isShowEdit);
//获取开始结束时间FormControl实例
const EndDate: string = formArray.controls[index].get('EndDate').value;
const StartDate: string =formArray.controls[index].get('StartDate').value;
if (EndDate === null || StartDate === null) return null;
//如果时间不合法,那就设置当前控件的错误状态 beginGtendDate为true
if (
Date.parse(control.value) > Date.parse(EndDate) ||
Date.parse(control.value) < Date.parse(StartDate)
) {
return { beginGtendDate: true };
}
}
return null;
}
}