Angular 'unexpected pipe imported by module' error


I have created a custom pipe that uses the DecimalPipe transform() method. I am using this pipe inside one of feature modules and I have to add both of those pipes to providers: [] (because MyCustomPipe uses DecimalPipe), like so:

index.ts:

@NgModule({
    imports: [
        MaterialModule,
        SharedModule
    ],
    declarations: [
        ...
    ],
    providers: [
        DecimalPipe,
        MyCustomPipe
    ...

My goal however is to not have to add DecimalPipe to a feature module in this way and have that dependence between MyCustomPipe and DecimalPipe 'hidden', so that who ever is consuming MyCustomPipe can just worry about importing MyCustomPipe from SharedModule. I tried to resolve this by trying to follow the SharedModule pattern and have the DecimalPipe exported from SharedModule (as I did with MyCustomPipe), like so:

shared.module.ts:

...import { DecimalPipe } from '@angular/common';

...export * from '../pipes/index';

@NgModule({
    imports: [
        CommonModule,
        FormsModule,
        HttpModule,
        DecimalPipe
    ],
    declarations: [
        LoginComponent,
        ErrorComponent,
        MyCustomPipe,
    ],
    exports: [
        CommonModule,
        HttpModule,
        LoginComponent,
        ErrorComponent,
        DecimalPipe,
        MyCustomPipe
    ]
})

However, when I try to do this I get the error "Error: (SystemJS) Unexpected pipe 'DecimalPipe' imported by the module 'SharedModule'. Please add a @NgModule annotation." . Now, I could add DecimalPipe to declarations: [] in SharedModule, but then I get the error warning me that DecimalPipe is declared both in SharedModule and CommonModule. I think this stems from my lack of understanding of the SharedModule pattern described in the docs. I am not 100% if this even is the right approach, as I have never tried to share a custom pipe that uses a build-in Angular pipe with feature modules.


Answers:


You don't have to worry about importing/declaring the inbuilt DecimalPipe along with your customPipe that uses it when you use/reuse it elsewhere in your app. Just declare the customPipe only. In your custom pipe's definition, just import the DecimalPipe like

import { DecimalPipe } from '@angular/common';

Then in the feature module that uses it just define them as part of the declarations array in @NgModule. If importing this feature module elsewhere in other feature module is supposed to identify this particular pipe being used in that new feature module, then mention this customPipe also part of the exports array declaration of the earlier feature module (that is being reused).

@NgModule({
  imports: [
    CommonModule,
    ...
  ],
  declarations: [
    CustomPipe
  ],
  exports: [
    CustomPipe // <-- do this only if you need this pipe to be available external to this ReusedFeatureModule when this module is 'imported' to other feature modules
  ]
})
export class ReusedFeatureModule { }

CustomPipe

import { Pipe, PipeTransform } from '@angular/core';
import { DecimalPipe } from '@angular/common';

@Pipe({
  name: 'customPipe'
})
export class CustomPipe implements PipeTransform {
 ...
 private originalDecimalPipe: DecimalPipe; // this variable will have  the inbuilt DecimalPipe inside the constructor body
 constructor () {
  this.originalDecimalPipe = new DecimalPipe('en-US'); // pass the current locale as the argument
 }
 transform(value: any): any { return <transformed-value>;} // implement your transform
}