如何将共享数据服务中的对象传入Angular 5验证器指令
如何在Angular自定义验证器指令中传入数组或正确注入共享服务?
嘿,我懂你现在卡在哪了——想让自定义的appCheckEmail验证器能校验输入邮箱是否在指定数组里,但不管是用@Input绑定非字符串值,还是直接注入共享服务都没搞定是吧?别慌,给你两种靠谱的解决方案,你按需选就行:
方案一:通过@Input正确传递数组(动态适配不同列表)
你之前用appCheckEmail={{test.value}}无效,是因为插值绑定会把所有值转成字符串,而我们要传的是数组对象,得用方括号包裹的属性绑定才行,而且要注意指令里的@Input命名技巧:
- 改造你的验证器指令,添加和指令选择器同名的
@Input属性:
import { Directive, Input } from '@angular/core'; import { AbstractControl, Validator, ValidationErrors } from '@angular/forms'; @Directive({ selector: '[appCheckEmail]' }) export class CheckEmailDirective implements Validator { // 这里用指令选择器作为@Input的别名,这样模板里绑定更简洁 @Input('appCheckEmail') emailList: string[] = []; validate(control: AbstractControl): ValidationErrors | null { const inputEmail = control.value?.trim(); if (!inputEmail) return null; // 空值交给required验证器处理 return this.emailList.includes(inputEmail) ? { emailExist: true } : null; } }
- 在模板里用属性绑定传递数组(不管是组件本地变量还是从共享服务里取的都可以):
<!-- 假设组件里已经定义了dealersList变量,比如从共享服务获取后赋值 --> <input type="email" name="email" id="email" [appCheckEmail]="dealersList" required >
这里一定要用[appCheckEmail]而不是appCheckEmail={{}},前者会传递原始的数组对象,后者只会传递字符串化后的内容。
方案二:正确注入共享数据服务(全局固定列表场景)
你说“无法直接注入共享数据服务”,大概率是服务的提供方式不对。先确保你的共享服务是全局可注入的:
- 配置SharedDataService的注入范围:
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' // 这个配置会让服务在整个应用里单例提供 }) export class SharedDataService { dealers: string[] = ['demo1@example.com', 'demo2@example.com']; // 如果是异步获取的,比如从API拉数据,可以加个方法: // getDealers(): Observable<string[]> { /* 你的API请求逻辑 */ } }
- 在验证器指令里正常注入服务,直接使用数组:
import { Directive } from '@angular/core'; import { AbstractControl, Validator, ValidationErrors } from '@angular/forms'; import { SharedDataService } from './shared-data.service'; @Directive({ selector: '[appCheckEmail]' }) export class CheckEmailDirective implements Validator { constructor(private sharedData: SharedDataService) { } validate(control: AbstractControl): ValidationErrors | null { const inputEmail = control.value?.trim(); if (!inputEmail) return null; return this.sharedData.dealers.includes(inputEmail) ? { emailExist: true } : null; } }
- 模板里只需要加上指令选择器即可,不用额外传值:
<input type="email" name="email" id="email" appCheckEmail required >
额外提示:如果数组是异步获取的怎么办?
如果dealers数组是从API异步拉取的,上面的同步验证器会因为初始数组为空导致校验失效,这时候要改成异步验证器:
import { AsyncValidator, AbstractControl, ValidationErrors } from '@angular/forms'; import { Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; import { SharedDataService } from './shared-data.service'; @Directive({ selector: '[appCheckEmail]' }) export class CheckEmailDirective implements AsyncValidator { constructor(private sharedData: SharedDataService) { } validate(control: AbstractControl): Observable<ValidationErrors | null> { const inputEmail = control.value?.trim(); if (!inputEmail) return of(null); // 假设共享服务里有个异步获取dealers的方法 return this.sharedData.getDealers().pipe( map(dealers => dealers.includes(inputEmail) ? { emailExist: true } : null) ); } }
内容的提问来源于stack exchange,提问作者MichaelE
相关产品推荐
相关产品推荐

