Angular权限验证指令报错StaticInjectorError(AppModule)[NgForOf->TemplateRef]求助
我帮你排查了一下,这个报错主要是三个地方出了问题,咱们一个个来解决:
先看你的问题场景
你写了一个ValidatePermissionDirective用来控制元素的显示权限,放在SharedModule里共享,然后在AdminPanelModule中导入使用,但触发了StaticInjectorError(AppModule)[NgForOf -> TemplateRef]错误,你的代码如下:
1. 权限指令代码
@Directive({ selector: '[appValidatePermission]' }) export class ValidatePermissionDirective implements OnInit { constructor(private templateRef: TemplateRef<any>, private viewContainerRef: ViewContainerRef , private dynamic: DynamicPermissionService) { } // tslint:disable-next-line:no-input-rename @Input('AccessName') AccessName: string; ngOnInit() { this.ValidateAccessPemission(this.AccessName); } ValidateAccessPemission(item: string) { if (this.FindAceess(item)) { console.log('in d true'); this.viewContainerRef.createEmbeddedView(this.templateRef); } else { console.log(' in dfalse'); this.viewContainerRef.clear(); } } FindAceess(acess: string): boolean { const find = this.dynamic.dynamicModel.filter(x => x.actionsVM.filter(z => z.actionEnglishName === acess)); if (find == null) { return false; } else { return true; } } }
2. SharedModule配置
@NgModule({ declarations: [ValidatePermissionDirective], imports: [ CommonModule ], exports: [ValidatePermissionDirective] }) export class SharedModule { static forRoot(): ModuleWithProviders { return { ngModule: SharedModule, providers: [ValidatePermissionDirective] }; } }
3. HTML使用方式
<span appValidatePermission [AccessName]='GetRoleList'> <router-outlet></router-outlet> </span>
问题原因分析
结构型指令用错了语法
你的指令依赖TemplateRef和ViewContainerRef,属于结构型指令,这类指令必须用*前缀的语法(比如*ngIf),Angular才会自动把包裹的内容转换成<ng-template>。你直接用appValidatePermission作为普通属性,Angular找不到对应的TemplateRef,就抛出了注入错误。SharedModule错误把指令注册成了服务
指令是声明式的DOM操作类,只需要在declarations里声明并exports出去让其他模块使用就行,不需要加到providers数组里。把指令放进providers会让Angular尝试把它当成服务注入,这完全不符合指令的设计逻辑。权限判断逻辑完全失效
你写的FindAceess方法里,x.actionsVM.filter(z => z.actionEnglishName === acess)返回的是一个数组,不管有没有匹配项,数组都是truthy值,所以dynamicModel.filter(...)会返回所有原数组元素,find永远不会是null,导致权限判断永远返回true,你的指令相当于没起作用。
逐一解决问题
1. 修正指令的使用方式
把HTML里的指令改成带*的结构型语法,推荐用<ng-container>(不会生成额外DOM节点):
<ng-container *appValidatePermission [AccessName]="GetRoleList"> <router-outlet></router-outlet> </ng-container>
或者简化成结构型指令的绑定语法:
<ng-container *appValidatePermission="GetRoleList"> <router-outlet></router-outlet> </ng-container>
2. 修复SharedModule的配置
移除forRoot里的providers配置,指令不需要作为服务提供:
@NgModule({ declarations: [ValidatePermissionDirective], imports: [CommonModule], exports: [ValidatePermissionDirective] }) export class SharedModule { static forRoot(): ModuleWithProviders<SharedModule> { return { ngModule: SharedModule }; } }
3. 修复权限判断逻辑
把FindAceess方法改成用some来判断是否存在匹配项,同时加可选链避免空指针:
FindAceess(acess: string): boolean { // 先判断dynamicModel是否存在,再检查有没有匹配的权限项 return this.dynamic.dynamicModel?.some(item => item.actionsVM?.some(action => action.actionEnglishName === acess) ) ?? false; }
some方法只要找到一个匹配项就会返回true,比filter更高效,也更符合判断逻辑。
这样修改之后,你的权限指令应该就能正常工作了,不会再出现注入错误,同时权限判断也能正确生效。
内容的提问来源于stack exchange,提问作者mr-dortaj

