如何在Angular中获取验证主题的组件引用?
问题描述
我需要编写一个指令绑定到组件上,以此订阅组件的验证状态变更事件,指令作为连接器使用。现有实现了IEntryValidationSubject接口的组件代码如下:
@Component({ selector: 'app-authors', templateUrl: './authors.component.html', styleUrls: ['./authors.component.scss'] }) export class AuthorsComponent implements OnInit, OnDestroy, IEntryValidationSubject { authorsForm: UntypedFormGroup; authorsFormArray: UntypedFormArray; subscriptions: Subscription = new Subscription(); authorsDataSource: FirstLastNameDataSource<AuthorViewModel>; private _isValid: BehaviorSubject<boolean> = new BehaviorSubject(true); public $validationStatusChange: Observable<boolean> = this._isValid.asObservable(); @Input() entryId: number; constructor( private fb: UntypedFormBuilder, public editorValidationService: EditorValidationService, public elementRef: ElementRef // ... 其他依赖 ) { this.editorValidationService.register(this, 'another'); // ... 其他初始化逻辑 } public isValid(): boolean { const controls = this.authorsFormArray && this.authorsFormArray.controls; let isValid = true; if (controls) { // 仅验证已填写的字段 isValid = controls .filter(control => this.isFilled(control.value)) .every(author => author.valid); } this._isValid.next(isValid); return isValid; } // ... 其他方法 }
为判断表单有效性编写的指令代码如下,尝试通过@Host()获取宿主组件引用但未成功:
@Directive({ selector: '[validateSubject]' }) export class ValidationDirective implements OnInit, OnDestroy { @Input() validateSubject: IEntryValidationSubject; constructor( @Host() @Optional() private host: IEntryValidationSubject, private validationService: EditorValidationService ) { } // ... 生命周期方法 }
解决方案
核心原因
Angular依赖注入系统无法直接识别接口类型(编译后接口元数据会被擦除),且组件默认不会自动注册为自身实现接口的提供者,导致@Host()无法找到对应的实例。
具体步骤
1. 在宿主组件中显式提供接口映射
修改AuthorsComponent的@Component装饰器,添加providers配置,将IEntryValidationSubject接口指向组件自身:
@Component({ selector: 'app-authors', templateUrl: './authors.component.html', styleUrls: ['./authors.component.scss'], providers: [ { provide: IEntryValidationSubject, useExisting: AuthorsComponent } ] }) export class AuthorsComponent implements OnInit, OnDestroy, IEntryValidationSubject { // ... 原有代码保持不变 }
2. 修正指令中的注入逻辑
移除冗余的@Input()(若不需要手动传入实例),确保@Host()能正确获取宿主组件实例:
@Directive({ selector: '[validateSubject]' }) export class ValidationDirective implements OnInit, OnDestroy { private validationSubscription?: Subscription; constructor( @Host() private host: IEntryValidationSubject, private validationService: EditorValidationService ) {} ngOnInit(): void { // 订阅宿主组件的验证状态变更事件 this.validationSubscription = this.host.$validationStatusChange.subscribe(isValid => { // 在此处理验证状态变更的业务逻辑 console.log('组件验证状态变更:', isValid); }); } ngOnDestroy(): void { // 取消订阅避免内存泄漏 this.validationSubscription?.unsubscribe(); } }
备选方案:通过@Input()手动传入实例
若不想修改组件的提供者配置,可在模板中直接将组件实例传入指令的输入属性:
<app-authors [validateSubject]="this"></app-authors>
此时指令可保留@Input(),无需依赖注入获取实例:
@Directive({ selector: '[validateSubject]' }) export class ValidationDirective implements OnInit, OnDestroy { @Input() validateSubject!: IEntryValidationSubject; private validationSubscription?: Subscription; constructor(private validationService: EditorValidationService) {} ngOnInit(): void { this.validationSubscription = this.validateSubject.$validationStatusChange.subscribe(isValid => { // 处理逻辑 }); } ngOnDestroy(): void { this.validationSubscription?.unsubscribe(); } }
内容的提问来源于stack exchange,提问作者trimmm0
相关产品推荐
相关产品推荐

