angular: Using multiple components in different modules causing "Type X is part of the declarations of 2 modules" error

I’m submitting a … (check one with “x”)

[ ] bug report
[x] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior

Right now you cannot import two directives of the same module

Expected/desired behavior

You can use same directives/components in multiple modules without errors.

What is the motivation / use case for changing the behavior?

Concept of the shared module with its shared resources is good for components that are used everywhere. But if you have a complex application (ours contain more then 50 modules and 1500 components, services and pipes all together) multiple components can be reused different way. For example QuestionListPage uses UserActiveListPanel from User module. Also PhotoListPage uses same UserActiveListPanel, and VideoListPage uses UserActiveListPanel. How do I reuse this panel? Best way is see is to provide it in directives of the component as it was before rc.5. But right now I can’t do it. But I can create lets say UserShareModule and put it there… its good, but if I put everything that is used by other modules from user module, i’ll LOT of things there unnecessary in most of times. Then what to do? Create UserActiveListPanelShareModule? It will create lot of such trash files. So what to do? Maybe we simply can provide same directives multiple times without having this annoying error Type X is part of the declarations of 2 modules?

If you tell me that its by design, then my answer is: in my opinion its a bad design.

Please tell us about your environment:

  • Angular version: 2.0.0-rc.5
  • Browser: [all ]
  • Language: [all]

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 64
  • Comments: 98 (26 by maintainers)

Most upvoted comments

Your question sounds like a support request.

Please use the issue tracker only for bugs and feature requests.

Use gitter and StackOverflow for support request.

as @brandonroberts saids, create a shared module like this:

import { NgModule }       from '@angular/core';
import { CommonModule }   from '@angular/common';
import { FormsModule }    from '@angular/forms';

import {SharedComponentA} from "./SharedComponentA";
import {SharedComponentB} from "./SharedComponentA";

@NgModule({
    imports: [
        CommonModule,
        FormsModule,

    ],
    declarations: [
      SharedComponentA,
      SharedComponentB

    ],
    providers: [
    ],
    exports: [
      SharedComponentA,
      SharedComponentB
    ]
})
export class SharedModule {}

then use the SharedModule like this…

import { NgModule }       from '@angular/core';
import { CommonModule }   from '@angular/common';
import { FormsModule }    from '@angular/forms';

import {SharedModule } from './SharedModule';

@NgModule({
    imports: [
        CommonModule,
        FormsModule,

        SharedModule

      //..
    ],
    declarations: [
     // ....
    ],
    providers: [
        // ....
    ]
})
export class PersonModule{}

If you want to use a component across multiple modules, you’ll need to create a “shared” module and add that component the shared module’s exports. Then you add that shared module into your other modules imports.

@vicb I think that you need to read more carefully before you close an issue.

where do you see a question here? :speachless:

No it really harms organization in a long run.

Lets bring an example. I have two modules. QuestionModule, PostModule and UserModule. QuestionModule and PostModule need UserListPanelComponent from a UserModule. How to handle such situation?

option1. Create a UserSharedModule and add there UserListPanelComponent. But it looks like we gonna put to UserSharedModule all other components too (lets say other 20 components out of 50 UserModule has), because other modules (30) also uses different components of the UserModule. QuestionModule (or any other that uses UserModule’s components) loads lot of stuff that he don’t really need. It loads all 20 components when it needs only one. So it seems to be a bad option.

option2. Create UserListPanelSharedModule. that shares only one component -UserListPanelComponent. Now I can load only one file and not worry that it loads all 20 components. But wait… its annoying and simply stupid to create one another separate file for each component you want to share. So, it definitely bad option.

Any good options here?

If you want to use the same Component you can maybe try to cheat angular by using extends. Try something like this.

@Component({
    selector: "selector",
    templateUrl: "/component.html"
})
class BaseComponent {}

export class AComponent extends BaseComponent {}
export class BComponent extends BaseComponent {}

No you have two components that are basically the same. To avoid conflicts you might add different selectors to the components.

This is extremely inconvenient, as well as being plain ugly. You should really be able to inherit components from a parent module, because I think a shared module is extremely ugly.

You’re going to end up with one huge shared module with all your components, which is one of the things I hate in more conventional platforms like .NET

I think you should be able to at least explicitly be able to share components between parent-child modules, in the sense of something like this:

@NgModule({
    imports: [
        CommonModule,
        FormsModule
    ],
    declarations: [
        Component1,
        Component2,
        // etc..
    ],
    expose: [ // Or really any word that would better describe what you're trying to do.
        Component1,
        Component2
    ]
})
export class AppModule{}

And then in your child module:

@NgModule({
    imports: [
        CommonModule,
        FormsModule
    ],
    inherit: [ // Inherit the exposed components from the parent module!
        Component1,
        Component2
    ]
})
export class SubModule{}

I’m sure there is a better way to do this. You just don’t want to have ten thousand components in a Shared module.

yeah I did it and it works. The problem is that it is very very inconvenient for multiple directives/components that are used only few times by other components.

I would have to agree that this is a big inconvenience. I have to create a module for something as trivial as one component.

Once you have your shared module setup it should be easier to add components to multiple modules. In the long run it helps you to organize your code into modules with a standard convention.

On Aug 10, 2016 4:26 PM, “Umed Khudoiberdiev” notifications@github.com wrote:

yeah I did it and it works. The problem is that it is very very inconvenient for multiple directives/components that are used only few times by other components.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/angular/angular/issues/10646#issuecomment-239009599, or mute the thread https://github.com/notifications/unsubscribe-auth/AACk49A-4QoQzcytHFasORcAgTbXJlftks5qekIhgaJpZM4JhYBD .

Seems pretty silly to have to do this extra work to be able to use a component thats meant to be shared… Feels like an extra layer of configuration on top of all the other configuration thats needed…

@DzmitryShylovich It’s immature syntactical idiocy to say you can create as many modules as you want when you know that whatever modules you create will ALL go into the same shared module. The only real difference is one was is very cluttered and the other has significantly more code. The problem remains!

I’m not understanding why this is such a hard concept to understand.

@zoechi Saying this thread is beating a dead horse is the wrong expression… It’s more like complaining that my wife packs every bit of clothes, shoes, and accessories she owns every time she goes somewhere because she doesn’t have the ability to just take the shit she’s actually going to use. That’s a better example.

They built it that way for technical reasons. Don’t expect this to change. Rather embrace how modules work instead of beating a dead horse.

I am also thinking about this. My Shared-Module has now nearly 30 components. Now i need to use one component in two different modules. So i need to import the whole Shared-Module twice in each component to only use one component? Is that not a big mistake against performance. What happens detailed during importing a module?

The problem here is that the current method is LESS performant than the desired method, not more.

prove it, then file a new issue with benchmarks.

How would you suggest I do that? Should I rewrite the framework to allow the desired behavior?

Why has there been no legitimate response to this? Why is is still closed?

This is a very big issue and needs to be fixed. I see no point in touting the benefits of componentization, then immediately stuffing all those components into one module that has to be loaded each and every time, no matter what. That’s pathetic!

Our adaptation of NG2 is being stalled by a couple of massive problems with NG2, and it would be nice for atleast one of them to be addressed in a meaningful way… atleast let us know you are working to fix the problem.

I wanted to figure out how to reuse a component between modules. Google brought me here. After reading this thread I just sighed. I’m not convinced by the shared module pattern described above.

I’d love to know how the teams at Google using Angular on large apps structure their shared component code.

@DzmitryShylovich Read the comment linked. he doesn’t explain or justify the restriction. He gives the thought behind shared module scoping and hierarchy, which is cool, but that’s not what I’ve been talking about.

@jcmordan

What do you prefere? less code or best performance?

Both of course, but that’s not the question here. The problem here is that the current method is LESS performant than the desired method, not more. The ability to load components and modules ONLY where they will be used, and not everywhere, is the desired behavior. I haven’t seen anyone say that components should be loaded multiple times if they are referenced multiple times, that’s what caching is for.

The seemingly undiscovered point is that we need not load and cache every module, component, pipe, directive, etc… every frackin time the app loads. I still haven’t seen a cogent argument or explanation for this.

Also, I’m not continuing with this conversation hoping that NG2 will get fixed (that would be nice though). I’m trying to find a reason for the madness. So far, I have several major problems with the NG2 architecture and I am evaluating other frameworks to find which one will/might be better for our project for the long term. So far, NG2 is still winning, but still doesn’t help when the architecture is suffering.

@kennygitchen what’s the problem with creating another shared module that contains only this one component?

Nobody said that you have to create just one shared module. You can create as many shared modules as you need, grouping the component by functionality (for example).

Is more code? yes, but how much that you have to scare about?

Of course this behaivior could be better, but I thinks this make sense, if you think about optimization and permormance, remember that just one instance of a shared component is create it.

What do you prefere? less code or best performance?

Agreed, this is a legitimate feature request and not a question requesting support. This should be reopened for discussion.

How so? Is this not a legitimate feature request thread?

Extreme cases are… well, extreme. Not really good for the discussion.

I did not find any problem with the current system until now. I do not create any “shared” named module only feature named modules where I import needed dependencies. From time to time I do need to reorganize a bit, I mean change the point where I import a specific dependency or create a new module that makes sense to “modularise” a feature.

I actually feel that the current implementation points you to good practices and to make you reevaluate your architecture from time to time.

I have found an explanation in Angular Docs:

What if I import the same module twice? That’s not a problem. When three modules all import Module ‘A’, Angular evaluates Module ‘A’ once, the first time it encounters it, and does not do so again.

That’s true at whatever level A appears in a hierarchy of imported modules. When Module ‘B’ imports Module ‘A’, Module ‘C’ imports ‘B’, and Module ‘D’ imports [C, B, A], then ‘D’ triggers the evaluation of ‘C’ which triggers the evaluation of ‘B’ which evaluates ‘A’. When Angular gets to the ‘B’ and ‘A’ in ‘D’, they’re already cached and ready to go.

Angular does not like modules with circular references so don’t let Module ‘A’ import Module ‘B’ which imports Module ‘A’.

@jusefb this usually means you’ve added the NgSelectOption to your declarations instead of importing the appropriate forms module. The rule is if you created the directive, you need to declare it. If you didn’t create it and it comes with a module, it doesn’t go in your declarations. Instead you add that module to your imports.

For your previous comment, if you are concerned with modules sharing components that other modules don’t need, then you organize further. I used the term “shared” module loosely because there doesn’t have to be just one. You can create a set of small modules to import into other modules to share components.

It’s funny to see, that this issue will be there for ever. This very opinionated design decision will be a point to reconsider usage of other SPA-Frameworks. It’s very interesting, that on the one hand angular allows a lot of configuration through decorators. On the other hand it adds a lot of hidden restrictions to this configuration and a lot of options to miss configure. So just at this point aurelia does a lot better job by removing all this configuration boilerplate.

So somehow this discussion is a symptom of a unbalanced design. Adding a lot of freedom while extremely restricting it at the same time because of other more or less important (dependent of the project goals) design decisions.

Who says we don’t want to make multiple modules? The original problem is that we can’t share the same component across multiple modules. So now we are forced to make one big shared module to make sure we don’t run into that problem.

On Thu, Jan 5, 2017 at 11:33 AM, Dzmitry Shylovich <notifications@github.com

wrote:

Nobody forces u to create only one shared module with 30 deps. U can crate as many modules as u want

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/angular/angular/issues/10646#issuecomment-270735288, or mute the thread https://github.com/notifications/unsubscribe-auth/ABCbNl1DIxeTvCr035wn7Q1GcDJGc8xzks5rPUVtgaJpZM4JhYBD .

@duannx … a component can be included in the declaration section only of one module - it is by design.

Any updates? This doesn’t really make sense. Rather than simply listing dependencies for your module and letting angular take care of injecting them you will end up just making a shared module that lists all the dependencies and import that into every module whether it needs 1 of the dependencies or 30.

Lets say now I need this component in a newly created module, what should I do? Declare this “another-shared-module” into the root module? Consolidate this “another-shared-module” with another “shared-module”? (In large application consolidation will most likely create a domino effect)

The main issue of the discussion of loading unnecessary component is not solved completely with this “another-shared-module” approach. It also adds complexity to the dependency management.

I remember using RequireJS, where I only load the components that I need in each module. I don’t have to load components that I don’t need.

And nowadays, people are using frameworks like Webpack where it is smart enough to create codesplits (bundle related JavaScript or resource files as one download) to help loading performance. With Webpack you are likely to load unnecessary components, but the framework is smart enough to minimise it (well to an extend, of course), you don’t have to do it manually.

I am new to Angular, please forgive and correct me, if I am not making sense.

Seems like community feedback is not going to be taken and we will have to load all the unnecessary code even if we only need one component in the SharedModule.

What if I have dozens of single-purpose components, that can be included by any number of other components (forms, subforms, views, etc)? For example: Consider an orderform, consisting of one component that has the customer information, one component that has a FormArray for each orderitem and then one component for each orderitem. And for when the orderform is locked, I have the same amount of components for presenting just a view (cannot be changed by the user).

Do I have to create an NgModule for each and every one of those components?

If I create just one NgModule for all the orderitem related components, it means that loading a view component will also load FormModule/ReactiveFormModule for example… That’s completely unneccesary.

If I create a single NgModule for all of it, it will be quite bloated and that will result in longer load times, which is also bad. (I’m using http/2, so bundling into one single huge file is a bad thing for me).

So currently I see no other way than to make one NgModule for each and every single component/subcomponent/modal/etc file in the application (in order to not affect load times), which will force me to make several dozen, if not hundreds, of them. 😕

The only way to solve this problem is have a well organized module structure, just like what angular itself did. However it is not possible in business logic. Some “pages” just share a similar UI component, for no reason and we can not group those component together like angular did because there are no relationship between them. If I started using “shared modules”, finally it will end up with having a huge “shared module” that declares everything, to make sure nothing is declared twice.

The current solution will be have multiple “shared module” with reasonable size. This will avoid importing all components when you only want to use one. However it is not convenient nor efficient.

I said about next situation.

“SharedModule”

import { ToolBarForm } from ‘…/jsonSchemaForm/forms/toolbar/index’; import { NgModule } from ‘@angular/core’; import { CommonModule } from ‘@angular/common’; import { FormsModule } from ‘@angular/forms’;

@NgModule({ imports: [ CommonModule, FormsModule, ], declarations: [ ToolBarForm ], exports: [ ToolBarForm ] }) export class SharedModule {}

“PersonalStaffDismissed” index.ts file

import { CommonModule } from ‘@angular/common’; import { FormsModule } from ‘@angular/forms’; import { NgModule, ApplicationRef } from ‘@angular/core’; import { RouterModule } from ‘@angular/router’; import { PersonalStaffDismissed } from ‘./staff’; import { SchemaFormModule } from “…/…/…/…/…/srcs/schema-form/schema-form.module”; import { SharedModule } from ‘…/…/…/…/system_module/extendes_modules’;

export const routes = [ { path: ‘’, component: PersonalStaffDismissed, pathMatch: ‘full’ } // (*) ];

@NgModule({ declarations: [ PersonalStaffDismissed, ], imports: [ CommonModule, FormsModule, SchemaFormModule, SharedModule, RouterModule.forChild(routes), ] })

In component “PersonalStaffDismissed” component “Toolbar” was nor declarated and it have error in browser.

For example, if i declareted “PersonalStaffDismissed” in “SharedModule” it was ok, because I used it in router (*).

brandonroberts: “If you want to use a component across multiple modules, you’ll need to create a “shared” module and add that component the shared module’s exports. Then you add that shared module into your other modules imports”

there is performance issue in your way. it should, like lib for system, loaded when need and can be shared by all after loaded

Hi, I have the same problem here. I try moving the common components to the AppModule. but then i got and error

Can’t bind to ‘option’ since it isn’t a known property of ‘panel-detail’

<panel-detail option="data"></panel-detail>

@kylecordes Right, but if you’ve upgraded to RC5 and you haven’t removed all your directives from your components, and one of those components is still including one of the old FORM_DIRECTIVES arrays, I could see why it would happen.

@mlc-mlapis Thank you for the reply but I believe you are still not understanding what I am saying, which is this:

  1. You don’t need the shared module if a parent is eager loading children. The parent can contain the component and both children will be able to use it.

  2. You do need the shared module if a parent is lazy loading children. The children will not see the component if you declare it in the parent so in this scenario you must use a shared module.

So I would say it is something to care about - otherwise you are in danger of creating a huge shared module with maybe hundreds of components and then end up loading that on a lazy route just to get access to one single component. So how you structure shared code is quite important I think. I imagine most large Angular projects will require several shared modules, not just one, for this reason. And on routes which are not lazy loaded, they might not need a shared module at all - they can simply put the component in the parent.

@raysuelzer if you want to use components, directives, pipes from module B in module A, you have to import B (or any other module that exports B) in A. What you import in AppModule doesn’t matter to module A except for services.

Well I’m sure it could be worst of course, but I think we should think about how to make it better.

I think the real solution here, performance and organization wise, is the option to lazy load a component (and it deps). This way you won’t be mind importing a huge module when only using several components and more importantly you won’t be loading + processing (parse/compile/storing etc) dozens of components for nothing in runtime.

Technically speaking there is no difference and no problem. But from organizing aspect this is creating a lot of noise. Imagine dozens of such components each requiring additional module file containing the exact same code.

I’m not saying this is impossible. I’m just saying there must be a better way.

+1

Separate module for each component is not practical. There should be a method to reuse components across different modules without creating for them a dedicated modules or some big shared module with all of them together (causing all of them to load when needing only one of them).

Multiple shared modules especially in combination with lazy loaded modules are important keys for good performance and easy maintenance. The main app module should be as optimized as possible.

@kennygitchen When you have a hundred products and each of them uses different combination of attributes it is not a work-around but the basic principe.

In extreme cases you create one module per one component and load the module programmaticaly when you want or in combination with lazy loaded modules through router.

“Shared” module work if componenet is componenet of a router, tlst it doesnt work.

@ootwch With the new module system, it will be most typical for third-party Angular based libraries to present themselves to your application as a module. So yes, they will need to be updated to embrace RC5+. However, in the meantime there is a fairly easy workaround. You can simply add a single file in your application which defines a module which includes the contents of the older (RC4 or less) angular based library you were using. Then depend on this module from each of your own modules. That should get you past the trouble between now and when those libraries are updated.

@brandonroberts and others - I think this error occurs when a component (either user-written or built-in) has been accidentally, implicitly, transitively included in more than one module - which can easily happen even without the now-deprecated “directives” list. Maybe that tip will make it easier to make a repro plunker. Still, I suspect it will turn out to be a “feature, not a bug”.

@mlc-mlapis The default module wrapping sounds great, and makes sense. I find myself wondering the same thing as I keep creating a module just to wrap a component for the purpose of sharing in other modules. Seems that should be implicit.

@kennygitchen

just one JS file contains everything / only one single shared module

Certainly not. Creating a module means adding 5 lines of code over the code for just a component, so it’s nothing that should be a problem.

There is an idea to have a so-called default module (when Ivy will be ready) which should allow to lazily-load only a single component.

I don’t think this thread is about what is the best practice, I think most of people here are not asking for what is the best practice to do this. Other than, this is quite a specific problem that people trying to get Angular to solve.

The issue here is really dependency management and probably, especially for people managing large applications with lazy loading components (loading components on the fly, so the app gets loaded in parts)

I have been working with a web application contains 60+ screens, and based on the configurations, each client gets different screens. Each screen implementation is complex enough to warrant its own module. So, we don’t want to load the whole application when the user hit the url the first time. The whole app download will probably exceed 5MB+ in size. For us to be able to manage the ‘dependencies’ probably, it will be easier to just declare the components in the module and let the code/framework sort out the duplications. You can argue this is custom but as there are quite a few people coming in this thread to express their ‘feedback’ as ‘this is not good enough’ (well at least I am), is probably something worth look into.

In situation like this, declaring shared module specifically for the combination of ‘screens’ will be mad, therefore there is no choice but to put all the shared components into one single shared module. That defects the purpose of splitting the code. Of course there is always a solution to a problem, such as declare a shared module for each, for example client, but the point is ‘we are giving our feedback to improve this framework’.

This might be an old concept now as most of the web apps I have been working are just one JS file contains everything. Therefore, putting all shared component as one shared module isn’t an issue at all.

cheers, Kenny

@mlc-mlapis Yeah. I khow it is by design but it is not the problem. The main question is how to share component between modules and the only answer is use share.module.ts. This way cause many annoying

each component HAS TO be declared only in one NgModule

I know that, that’s the reason I wrote here… Why in just one? I don’t see any logic behind having to create boiler-plate module for each component I want to be accessible in more modules (are we in Java world where boiler-plate is worshiped?). It feels like a random utterly unpractical restriction.

@chaiwa-berian a feature module and a shared module is the same thing. If you import a module it’s a shared module 😉 Perhaps you can differentiate between a module that you import only once, for example to wrap a part of your application in a module. For example AppModule is usually not a shared module. If you have a module that you import in different other modules then it’s definitely a shared module.

There is a problem with this module: 1 It is not possible to include two or more component 2 Do not work the trick with a share module 3 It is not possible to declare the component globally, to be visible in loadable Due to the first two problems, the module is not possible to use angular2. This is the important module for angular2. If this is required to change the framework, I think it should be done only official. Thx)