Estus Flask
Estus Flask

Reputation: 222319

NgModule nested forRoot

Considering that there is a module

@NgModule({
    imports: [
        Ng2Webstorage.forRoot({ prefix: 'SOME_PREFIX' }),
        FooModule.forRoot(...),
        BarModule,
    ],
    exports: [
        Ng2Webstorage,
        FooModule,
        BarModule,
    ]
})
class FeatureModule {
    static forRoot(config): ModuleWithProviders {
        return {
            ngModule: FeatureModule,
            providers: [...]
        };
    }
}

How can it pass prefix to Ng2Webstorage.forRoot dynamically? Like:

@NgModule({
    imports: [
        BarModule,
    ],
    exports: [
        Ng2Webstorage,
        FooModule,
        BarModule,
    ]
})
class FeatureModule {
    static forRoot(config): ModuleWithProviders {
        return {
            ngModule: FeatureModule,
            imports: [
                Ng2Webstorage.forRoot({ prefix: config.name }),
                FooModule.forRoot(config.foo)
            ],
            providers: [...]
        };
    }
}

...
imports: [FeatureModule.forRoot({ name: `ANOTHER_PREFIX` }), ...]
...

Is it possible to have nested forRoot calls?

It looks like ModuleWithProviders doesn't accept imports.

Upvotes: 3

Views: 1989

Answers (2)

Bart Verkoeijen
Bart Verkoeijen

Reputation: 17723

It is possible by explicitly redefining the providers in forRoot(). Other elements of the package can be imported and exported in the usual way.

Note that I use Array.concat() to easily chain multiple modules.

@NgModule({
    imports: [
        BarModule,
    ],
    exports: [
        Ng2Webstorage,
        FooModule,
        BarModule,
    ]
})
class FeatureModule {
    static forRoot(config): ModuleWithProviders {
        return {
            ngModule: FeatureModule,
            /* Explicitly redefine the providers from imported/exported modules. */
            providers: [].concat(
                Ng2Webstorage.forRoot({ prefix: config.name }).providers,
                FooModule.forRoot(config.foo).providers
            )
        };
    }
}

EDIT:

The above doesn't work when you use AOT compilation. Instead, use the following workaround with static exported function AND typed argument, e.g. config.

export function ng2WebstorageProviders(name: string) {
  return Ng2Webstorage.forRoot({ prefix: name }).providers;
}

export function fooProviders(foo: object) {
  return FooModule.forRoot(foo).providers;
}

@NgModule({
  imports: [
    BarModule,
  ],
  exports: [
    Ng2Webstorage,
    FooModule,
    BarModule,
  ]
})
class FeatureModule {
  static forRoot(config: {name: string, foo: object}): ModuleWithProviders {
    return {
      ngModule: FeatureModule,
      /* Explicitly redefine the providers from imported/exported modules. */
      providers: [
        ...ng2WebstorageProviders(config.name),
        ...fooProviders(config.foo)
      ]
    };
  }
}

For reference:

Upvotes: 2

yurzui
yurzui

Reputation: 214017

Yes, you're right. We can't pass imports to ModuleWithProviders import.

Here is how angular collects data from such import:

} else if (importedType && importedType.ngModule) {
    const moduleWithProviders: ModuleWithProviders = importedType;
    importedModuleType = moduleWithProviders.ngModule;
    if (moduleWithProviders.providers) {
      providers.push(...this._getProvidersMetadata(
          moduleWithProviders.providers, entryComponents,
          `provider for the NgModule '${stringifyType(importedModuleType)}'`, [],
          importedType));
}

https://github.com/angular/angular/blob/4.3.x/packages/compiler/src/metadata_resolver.ts#L448-L456

We can override provider declated within Ng2Webstorage.forRoot() by passing the same provider within ModuleWithProviders.providers like this:

import {Ng2Webstorage, WEBSTORAGE_CONFIG} from 'ngx-webstorage';

@NgModule({
  imports: [
    Ng2Webstorage.forRoot()
  ],
  ...
})
export class FeatureModule {
  static forRoot(config): ModuleWithProviders {
    return {
      ngModule: FeatureModule,
      providers: [
        { provide: WEBSTORAGE_CONFIG, useValue: config }
      ]
    };
  }
}

Upvotes: 4

Related Questions