Angular 5自定义DefaultPipe在子路由组件中无法使用问题
我之前在Angular 5中实现了一个简单的DefaultPipe,用来在值为空时返回备选内容,代码如下:
import { Pipe, Injectable } from '@angular/core'; @Pipe({ name: "default" }) @Injectable() export class DefaultPipe { transform(value: string, fallback: string): string { let image = ""; if (value) { image = value; } else { image = fallback; } return image; } }
使用的时候直接在模板里添加管道:
<div> {{ 'somthing' | default }} </div>
一开始我把这个管道声明在了app.module.ts的declarations数组里:
@NgModule({ declarations: [ AppComponent, DefaultPipe // 声明管道 ], imports: [ .... ], providers: [ .... ], bootstrap: [AppComponent] }) export class AppModule { }
这时候在app.component.html这类根模块下的组件里使用完全正常,但在子路由对应的组件(比如LoginComponent)里使用时,直接报了模板解析错误:
compiler.js:486 Uncaught Error: Template parse errors: The pipe 'default' could not be found ("
{{[ERROR ->] 'somthing' | default }} "): ng:///AppRoutingModule/LoginComponent.html@75:6
at syntaxError (compiler.js:486)
at TemplateParser.webpackJsonp../node_modules/@angular/compiler/esm5/compiler.js.TemplateParser.parse (compiler.js:24674)
at JitCompiler.webpackJsonp../node_modules/@angular/compiler/esm5/compiler.js.JitCompiler._parseTemplate (compiler.js:34629)
at JitCompiler.webpackJsonp../node_modules/@angular/compiler/esm5/compiler.js.JitCompiler._compileTemplate (compiler.js:34604)
at compiler.js:34505
at Set.forEach ()
at JitCompiler.webpackJsonp../node_modules/@angular/compiler/esm5/compiler.js.JitCompiler._compileComponents (compiler.js:34505)
at compiler.js:34375
at Object.then (compiler.js:475)
at JitCompiler.webpackJsonp../node_modules/@angular/compiler/esm5/compiler.js.JitCompiler._compileModuleAndComponents (compiler.js:34374)
问题原因
这其实是Angular模块的作用域限制导致的:在AppModule中声明的组件、指令、管道,只能在该模块直接关联的组件中使用。而路由模块里的组件属于独立的模块上下文,无法直接访问根模块里声明的管道。
解决步骤
要解决这个问题,我们需要把共享的管道放到一个SharedModule里,然后在需要使用的模块中导入这个共享模块:
- 创建
SharedModule
这个模块专门用来存放需要跨模块共享的组件、指令和管道,并且通过exports数组暴露它们:
import { NgModule } from '@angular/core'; import { DefaultPipe } from './core/pipes/default.pipe'; @NgModule({ declarations: [DefaultPipe], exports: [DefaultPipe] }) export class SharedModule { }
- 在
AppModule中导入SharedModule
这样根模块下的组件依然能正常使用管道:
@NgModule({ declarations: [ AppComponent, ], imports: [ ... // 其他已导入的模块 SharedModule ], providers: [ .... ], bootstrap: [AppComponent] }) export class AppModule { }
- 在路由模块(
AppRoutingModule)中导入SharedModule
这一步是关键,让路由模块下的子组件也能访问到这个管道:
@NgModule({ declarations: [ .... ], imports: [ .... SharedModule ], exports: [ RouterModule, ] }) export class AppRoutingModule { }
做完这三步之后,无论是根组件还是路由子组件,都能正常识别并使用default管道了。
内容的提问来源于stack exchange,提问作者Ehsan Zargar Ershadi

