Angular6出现无法访问'ngInjectableDef'、depDefToken未定义错误
Angular6 注入继承抽象类的服务时报错
无法访问属性"ngInjectableDef",depDefToken未定义 问题解决 问题表现
- 工单系统首次点击带会话文本编辑器的工单、F5刷新工单列表后再次点击工单时,工单详情无法正常加载
- 只有先跳转其他页面再返回点击工单才能正常展示
- 控制台报错指向文本编辑器组件,移除该组件后问题消失
报错截图:
排查过程
- 移除TextEditor构造函数中
private imageValidator: TextEditorImageValidator注入声明后,报错消失 - 进一步定位发现,移除
TextEditorImageValidator对父类UploadValidator的继承后问题解决 - 最终确认问题出在抽象类
UploadValidator的依赖注入配置上
根本原因
该问题是Angular 6版本的依赖注入限制导致的:
- 抽象类本身没有添加
@Injectable()装饰器,Angular DI系统无法识别它构造函数里的依赖项 - 子类
TextEditorImageValidator虽然加了@Injectable(),但Angular 6不会自动处理父类构造函数的依赖注入,父类依赖的Settings、Toast、Translations三个来自CoreModule的服务无法被正确注入,导致注入链断裂,触发depDefToken未定义报错 - 首次加载或者刷新后注入器还未完成对应Core服务的实例化缓存,所以直接访问就会报错,跳转其他页面后服务被实例化缓存,再访问就正常,完全匹配问题表现
解决方案
给抽象父类UploadValidator加上@Injectable()装饰器即可,不需要修改其他逻辑:
import { Injectable } from '@angular/core'; // 新增导入 import { Settings } from '../../core/config/settings.service'; import { Toast } from '../../core/ui/toast.service'; import { UploadValidation } from './validations/upload-validation'; import { UploadedFile } from '../uploaded-file'; import { Translations } from '../../core/translations/translations.service'; @Injectable() // 新增装饰器 export abstract class UploadValidator { protected validations: UploadValidation[] = []; public showToast: boolean; constructor( protected settings: Settings, protected toast: Toast, protected i18n: Translations ) {} // 原有逻辑不需要修改 public validate(file: UploadedFile): {failed: boolean, errorMessage?: string} { if ( ! this.validations.length) this.initValidations(); const failed = this.validations.find(validation => { return validation.fails(file); }); if (failed && this.showToast) { this.openErrorToast(failed.errorMessage); } return {failed: !!failed, errorMessage: failed ? failed.errorMessage : null}; } public validateWithToast(file: UploadedFile) { const response = this.validate(file); this.openErrorToast(response.errorMessage); return response; } protected openErrorToast(message: string) { this.toast.open(message); } protected abstract initValidations(); }
如果加了之后还是有问题,可以在子类的构造函数里显式注入父类需要的依赖再传递给父类:
@Injectable({ providedIn: 'root' }) export class TextEditorImageValidator extends UploadValidator { protected readonly DEFAULT_MAX_SIZE_MB = 3; // 新增构造函数,显式注入依赖传递给父类 constructor( protected settings: Settings, protected toast: Toast, protected i18n: Translations ) { super(settings, toast, i18n); } protected initValidations() { const validations = [ new FileSizeValidation( {maxSize: convertToBytes(this.DEFAULT_MAX_SIZE_MB, 'MB')}, this.i18n ), new FileTypeValidation({types: ['image']}, this.i18n), ]; this.validations.push(...validations); } }
修改完成后不需要注释任何原有逻辑,ImageValidator的功能可以完全保留,也不会再出现注入报错。
内容的提问来源于stack exchange,提问作者cilies38
相关产品推荐
相关产品推荐

