Angular 2 - Pipe reuse in multiple modules - error not found or duplicate definition
Asked Answered
V

1

36

Im working on angular 2 final release.

I have declared two modules: main app and one for the settings page.

The main module is declaring globally pipes. This module is also including the settings module.

app.module.ts

@NgModule({
    imports: [BrowserModule, HttpModule, routing, FormsModule, SettingsModule],
    declarations: [AppComponent, JsonStringifyPipe],
    bootstrap: [AppComponent]
})
export class AppModule { }

settings.module.ts

@NgModule({
    imports: [CommonModule, HttpModule, FormsModule, routing],
    declarations: [SettingsComponent],
    exports: [SettingsComponent],
    providers: []
})
export class SettingsModule { }

When trying to use the pipe in the settings module I'm getting an error that the pipe could not be found.

zone.min.js?cb=bdf3d3f:1 Unhandled Promise rejection: Template parse errors:
The pipe 'jsonStringify' could not be found ("         <td>{{user.name}}</td>
                    <td>{{user.email}}</td>
                    <td>[ERROR ->]{{user | jsonStringify}}</td>
                    <td>{{ user.registered }}</td>
                </tr"): ManageSettingsComponent@44:24 ; Zone: <root> ; Task: Promise.then ; Value: Error: Template parse 

If I include the pipe into the settings module it complains about the two modules having same pipe.

zone.min.js?cb=bdf3d3f:1 Error: Error: Type JsonStringifyPipe is part of the declarations of 2 modules: SettingsModule and AppModule! Please consider moving JsonStringifyPipe to a higher module that imports SettingsModule and AppModule. You can also create a new NgModule that exports and includes JsonStringifyPipe then import that NgModule in SettingsModule and AppModule.

json-stringify.pipe.ts

@Pipe({name: 'jsonStringify'})
export class JsonStringifyPipe implements PipeTransform {
    transform(object) {
        // Return object as a string
        return JSON.stringify(object);
    }
}

Any idea about this?

Vervain answered 13/10, 2016 at 7:41 Comment(0)
P
89

If you want to use the pipe in a different module, then add the module where the pipe is declared to imports: [...] of the module where you want to re-use the pipe, instead of adding it to declarations: [] of multiple modules.

For example:

@NgModule({
    imports: [],
    declarations: [JsonStringifyPipe],
    exports: [JsonStringifyPipe]
})
export class JsonStringifyModule { }
@NgModule({
    imports: [
      BrowserModule, HttpModule, routing, FormsModule, SettingsModule,
      JsonStringifyModule],
    declarations: [AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
@NgModule({
    imports: [
       CommonModule, HttpModule, FormsModule, routing, 
       JsonStringifyModule],
    declarations: [SettingsComponent],
    exports: [SettingsComponent],
    providers: []
})
export class SettingsModule { }
Pottle answered 13/10, 2016 at 7:42 Comment(8)
Thanks for the answer... Why do I need to create a module for pipes? Why defining the pipe in the global module is not enough to make the pipe available to other modules?Vervain
Why is a good question. Because Angular2 is designed this way. I guess that doesn't help much ;-). The NgModule concept was introduced to make lazy loading work with offline template compilation and I guess they had good reasons to design it this way. Angular just needs to know where components, directives, pipes, and services are used to be able to create small and efficient code that works with lazy loading and offline compilation.Mourn
You don't need to create a module for every pipe. You can put as many reusable components, directives, pipes, and services in such a module. But you need to import it everywhere where one of these parts are used.Mourn
I think that I just confused things that you can do in components and modules. Components seems to have a hierarchy - services registered as providers for a component can be inherit by other components. That does not apply to modules. In my case, app.module and settings.module are independent modules. App.module knows only exports from settings.module. Settings.module does not know about App.module. Hopefully Im understanding it properly.Vervain
Sounds like you got it ;-)Mourn
@GünterZöchbauer Hi! Sorry to always bother you throughout all SO. But, If my Pipe Module loads a .json with the translations and I include this module in all places where I need it... I will be loading this .json many times, right? Is there a way to avoid this and still have access to that translation Pipe (And therefore, have access to the pipe's module) in the entire App?Alphonse
If the loading code is in a service provided in @NgModule() (and inject it to the pipe), you can control it in the service. This service will exist only exactly once in your application no matter how often you use the pipe and if the service makes the call only once (see also #36272399) If your Pipe Module is lazy loaded you need to implement forRoot() and import the module in the AppModule to ensure a single service instance.Mourn
@GünterZöchbauer Brilliant as always. I will look into this right now. Thanks! :DAlphonse

© 2022 - 2024 — McMap. All rights reserved.