angular 自定义验证器
<p>先说"响应式表单"的用法</p><p> </p>
<p>新建的文件,用来写自定义验证器</p>
<div class="cnblogs_code">
<pre>import { AbstractControl } from "@angular/forms"<span style="color: rgba(0, 0, 0, 1)">;<br>
//control是我们要验证的表单控件,
export </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> beginWith(control: AbstractControl) {
const result </span>= /^13/<span style="color: rgba(0, 0, 0, 1)">.test(control.value);
</span><span style="color: rgba(0, 0, 255, 1)">return</span> result ? <span style="color: rgba(0, 0, 255, 1)">null : </span>{'beginWith': {value: control.value}}; <br>}</pre>
</div>
<p>上面返回语句中的"beginWith"是我们自定义的一个错误类型名,如果被验证的控件不满足我们自定义的这个验证规则, 控件元素的实例对象</p>
<p> </p>
<p>在组件类文件中</p>
<div class="cnblogs_code">
<pre>//要引用自定义验证器的文件,并且引入表单相关类<br>import { beginWith } from '....../上面定义验证器函数的文件名'<span>; </span></pre>
<pre><span style="color: rgba(0, 0, 0, 1)">import { FormGroup, FormControl, Validators } from </span>'@angular/forms'; //Validators是ng自带的内置验证器类,里面有一些对html5验证规则的封装方法.<br><br>...<br><br></pre>
<div>
<div> //在constructor中定义表单控件实例,并用内置验证器和自定义验证器始初化</div>
<div> this.heroForm = new FormGroup({ </div>
<div> phone: new FormControl('蝙蝠侠', )</em></em></div>
<div> });</div>
<div> </div>
<div> //一定要加上这个getter属性,这样在模板中才能取到name,下面模板中name.errors中的name就是通过这个getter方法取到的
<div> get phone() { return this.heroForm.get('name'); }</div>
</div>
</div>
</div>
<p> </p>
<p>在模板中</p>
<div class="cnblogs_code">
<pre><form ="heroForm" novalidate>
<input id="phone" name="phone" formControlName="phone" autocomplete="off">
<div *ngIf="phone.invalid && (phone.dirty || phone.touched)" class="alert alert-danger">
<div *ngIf="phone.errors.required"><span style="color: rgba(0, 0, 0, 1)">
必填
</span></div>
<div *ngIf="phone.errors.minlength"><span style="color: rgba(0, 0, 0, 1)">
至少4个字母
</span></div>
<div *ngIf="phone.errors.beginWith"><span style="color: rgba(0, 0, 0, 1)">
必须是13
</span></div>
</div>
</form></pre>
</div>
<p> </p>
<p>上面定义的验证器中的正则表达式是写死了, 可以改造一下, (这也是官方文档的例子https://angular.cn/guide/form-validation#adding-to-reactive-forms):</p>
<div class="cnblogs_code">
<pre>export <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> beginWith(regExp: RegExp): ValidatorFn {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> (control: AbstractControl): {: any} | <span style="color: rgba(0, 0, 255, 1)">null</span> =><span style="color: rgba(0, 0, 0, 1)"> {
const isMatch </span>=<span style="color: rgba(0, 0, 0, 1)"> regExp.test(control.value);
</span><span style="color: rgba(0, 0, 255, 1)">return</span> isMatch ? null : {'beginWith': {value: control.value}}<span style="color: rgba(0, 0, 0, 1)">;
};
}</span></pre>
</div>
<p> 之前的写法其实就是直接export(导出)一个验证器函数(ValidatorFn),这个修改的写法就是个工厂函数,即调用它时要传进来一个正则表达式,它会返回一个使用这个正则表达式创建的验证器函数(ValidatorFn),ValidatorFn是一个函数接口,参数为一个表单控件对象,返回值是一个错误信息对象或null(如果没有错误).</p>
<p> </p>
<p>相应的组件类中的创建表单对象的代码也要改下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">this</span>.heroForm = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FormGroup({
name: </span><span style="color: rgba(0, 0, 255, 1)">new</span> FormControl('蜘蛛侠', )
});</span></pre>
</div>
<p> </p>
<p> </p>
<p> "响应式表单"的实现方式需要在表单组件类所在模块( 可能是根模块 )引入ReactiveFormsModule,</p>
<div class="cnblogs_code">
<pre>import { FormsModule, ReactiveFormsModule } from '@angular/forms';</pre>
</div>
<p> </p>
<p>接下来看下模板驱动表单的实现方式:</p>
<p>用自定义指令的方式将上面写自定义验证器进行包装 : 官方的原文:必须创建一个指令,它会包装这个验证器函数。我们使用 NG_VALIDATORS 令牌来把它作为验证器提供出来. https://angular.cn/guide/form-validation#adding-to-reactive-forms</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 自定义验证器</span>
import { ValidatorFn, AbstractControl, <span style="color: rgba(255, 0, 0, 1)">NG_VALIDATORS</span>, <span style="color: rgba(255, 0, 0, 1)">Validator</span> } from "@angular/forms"<span style="color: rgba(0, 0, 0, 1)">;
import { <span style="color: rgba(255, 0, 0, 1)">Directive</span>, <span style="color: rgba(255, 0, 0, 1)">Input</span> } from </span>"@angular/core"<span style="color: rgba(0, 0, 0, 1)">;</span>
<span style="color: rgba(192, 192, 192, 1)">
export function beginWith(nameRe: RegExp): ValidatorFn {
return (control: AbstractControl): { : any } | null => {
const result = nameRe.test(control.value);
return result ? null : { 'beginWith'</span><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(192, 192, 192, 1)">: { value: control.value } };
};
}</span>
@Directive({
selector: </span>''<span style="color: rgba(0, 0, 0, 1)">, <span style="color: rgba(0, 128, 0, 1)">//在模板中的属性指令就要写成 phone="..."</span>
providers: [{
provide: NG_VALIDATORS, <span style="color: rgba(0, 128, 0, 1)">//这里我还没太搞弄,参考下官方文档吧</span>
useExisting: <span style="color: rgba(255, 102, 0, 1)">ForbiddenValidatorDirective</span>, <span style="color: rgba(0, 128, 0, 1)">//这个属性的意思官方文档上写的我也没太懂,总之呢要和下面类名一致</span>
multi: </span><span style="color: rgba(0, 0, 255, 1)">true <span style="color: rgba(0, 128, 0, 1)">//官方文档是说要想让一个控件同时支持多个验证器就要写 multi: true</span></span><span style="color: rgba(0, 0, 0, 1)">
}]
})
export class <span style="color: rgba(255, 102, 0, 1)">ForbiddenValidatorDirective</span> implements <span style="color: rgba(255, 0, 0, 1)">Validator</span> {
@Input(</span>'phone'<span style="color: rgba(0, 0, 0, 1)">) regExp_str: string; <span style="color: rgba(0, 128, 0, 1)">//通过模板上的属性指令取到的字符串值</span>
validate(control: AbstractControl): { : any } </span>| <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)"> {
const regExp </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> RegExp(<span style="color: rgba(0, 0, 255, 1)">this</span>.regExp_str, 'i'<span style="color: rgba(0, 0, 0, 1)">); <span style="color: rgba(0, 128, 0, 1)">//创建正则表达式对象</span>
const validatFn </span>=<span style="color: rgba(0, 0, 0, 1)"> beginWith(regExp); <span style="color: rgba(0, 128, 0, 1)"> //直接调用上面定义的工厂函数, 它返回的是一个验证器函数
</span></span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.regExp_str ? validatFn(control) : <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; <span style="color: rgba(0, 128, 0, 1)">//然后调用这个验证器, control就是当前指令所属的表单控件</span>
}
}</span></pre>
</div>
<p> </p>
<p> </p>
<p>修改组件类的代码:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">...</span><span style="color: rgba(0, 0, 0, 1)">
export class MyApp {
</span><span style="color: rgba(0, 0, 0, 1)">...
//"模板驱动式表单"的数据就直接用类属性定义
hero </span>=<span style="color: rgba(0, 0, 0, 1)"> {
phone: </span>'13333333333'<span style="color: rgba(0, 0, 0, 1)">
};
constructor() {
<span style="color: rgba(0, 128, 0, 1)">// </span></span><span style="color: rgba(0, 128, 0, 1)">this.heroForm = new FormGroup({
// name: new FormControl('王宁', )
// });</span></span><span style="color: rgba(0, 0, 0, 1)">
}
<span style="color: rgba(0, 128, 0, 1)">//get name() { </span></span><span style="color: rgba(0, 128, 0, 1)">return this.heroForm.get('name'</span><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 128, 0, 1)">); }
</span>}</span></pre>
</div>
<p> </p>
<p> </p>
<p>然后 修改一下模板</p>
<div class="cnblogs_code">
<pre><form>
<input id="phone" name="phone" required minlength="11" phone="^13" [(ngModel)]="hero.phone"<span style="color: rgba(255, 0, 0, 1)"> #phone="ngModel"</span> autocomplete="off">
<div *ngIf="phone.invalid && (phone.dirty || phone.touched)" >
<div *ngIf="phone.errors.required"><span style="color: rgba(0, 0, 0, 1)">
必填
</span></div>
<div *ngIf="phone.errors.minlength"><span style="color: rgba(0, 0, 0, 1)">
至少11位数
</span></div>
<div *ngIf="phone.errors.beginWith"><span style="color: rgba(0, 0, 0, 1)">
手机号必须是13开头
</span></div>
</div>
</form></pre>
</div>
<p> </p>
<p>"模板驱动式表单"中, 需要定义模板变量 #xxx="ngModel" (就是上面的#phone), 下面的错误提示DIV中用的phone.invalid 和 phone.dirty 等,其中的phone就是这个模板变量xxx,即指向被绑定的数据模型,这里是hero.phone</p>
<p> </p>
</div>
<div id="MySignature" role="contentinfo">
喜欢的话,请点赞,转发、收藏、评论,谢谢!<br><br>
来源:https://www.cnblogs.com/johnjackson/p/11122030.html
頁:
[1]