Angular module fabric

Viewed 263

I have a following module

@NgModule({
  declarations: [
    AgPaginationComponent,
    AgGridNoRowsComponent,
    // a huge list of components
  ],
  exports: [AgPaginationComponent, AgGridModule],
  imports: [
    CommonModule,
    InputsModule,
    FormsModule,
    NgbPaginationModule,
    NgbPopoverModule,
    AgGridModule.withComponents([
      AgGridNoRowsComponent,
      // the same huge list from declarations
    ]),
    PipesModule,
  ]
})
export class MyAgGridAddonsModule { }

You see here that it's possible to configure AgGridModule by specifying a list of components in withComponents array. The idea behind MyAgGridAddonsModule module was to create one module that I can use every time when I need to initialize AgGridModule. But turns out the module is growing too fast and has too many components under AgGridModule.withComponents declaration. Now I want to have a possibility to specify which dependencies I want to use each particular time but in the same time copy base configuration that is the same for every case.

I want to accomplish something like

@NgModule({
  imports: [
    MyAgGridAddonsModule.withComponents([
      MyAgInputFilter,
      MyAgLiveSearchFilter,
      MyAgSelectFilter,
      MyAgDateCellRenderer,
    ])
  ]
})
export class MyAnotherModule { }

And the array of components from MyAgGridAddonsModule.withComponents should be passed down to MyAgGridAddonsModule:

@NgModule({
  declarations: [
    AgPaginationComponent,
    AgGridNoRowsComponent,
    // components passed down from MyAnotherModule
  ],
  exports: [AgPaginationComponent, AgGridModule],
  imports: [
    CommonModule,
    InputsModule,
    FormsModule,
    NgbPaginationModule,
    NgbPopoverModule,
    AgGridModule.withComponents([
      // components passed down from MyAnotherModule
      AgGridNoRowsComponent
    ]),
    PipesModule,
  ]
})
export class MyAgGridAddonsModule { }

Is it even possible? Thanks.

2 Answers

You can have a static withComponents(c: any[]) method and use ANALYZE_FOR_ENTRY_COMPONENTS DI token (if not using ivy) in your MyAgGridAddonsModule to register entry components that you'll pass from other modules -

// common ag grid entry components
const commonAgGridComponents: any[] = [RedComponentComponent];
@NgModule({    
  imports: [AgGridModule.withComponents(commonAgGridComponents)],
  exports: [AgGridModule]
})
export class AgGridCommonModule { 
  static withComponents(components: any[]) {
     return {
      ngModule: AgGridCommonModule,
      providers: [{
        provide: ANALYZE_FOR_ENTRY_COMPONENTS,
        useValue: components,
        multi: true
      }]
    };
  }
}

Then in your MyAnotherModule, import this AgGridCommonModule by passing the extra entry components -

@NgModule({
  imports:      [ AgGridCommonModule.withComponents(
            [GreenComponentComponent]
        ) ]
})
export class MyAnotherModule { }

Please checkout this stackBlitz for AgGridModule. AgGridCommonModule is a wrapper for AgGridModule where you pass the list of entry components via withComponents() method from any other module.

What I would do is define the shared components inside the WithComponents section, but for the other components define them as frameworkComponents inside the component.ts that uses the grid.

If you have a grid-component that you know is only going to be part of a particular grid, you can declare them in the component's module as normal components. If the component will likely be shared by another grid, you will need to create a module that exports the component to be used, since you can't declare the same component in 2 modules. This shared-module could also be used to replace withComponents, but would require the additional tying of frameworkComponents at each grid-component, which it sounds like you are trying to avoid.

Related