Search code examples
angulartypescriptangular-factory

Angular 4.x - function calls are not supported. Consider replacing the function or lambda with a reference to an exported function


I'm trying to provide a way to customize a service, by using a static forRoot(), but...

I get the following error - even though I have exported the menuServiceFactory function to use as the factory.
I've also tried exporting it as a const value.

ERROR in Error: Error encountered resolving symbol values statically. Calling function 'MenuModule', function calls are not supported. Consider replacing the function or lambda with a reference to an exported function, resolving symbol AppModule in ...

Relevant code -

import { NgModule, ModuleWithProviders, SkipSelf, Optional } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MenuComponent } from './menu.component';
import { MenuService } from './menu.service';
import { MdMenuModule, MdToolbarModule, MdButtonModule } from '@angular/material';
import { FlexLayoutModule } from '@angular/flex-layout';
import { SecurityModule, SecurityService } from '@savantly/ngx-security';

@NgModule({
  imports: [
    CommonModule,
    MdMenuModule, MdToolbarModule, MdButtonModule, FlexLayoutModule, SecurityModule
  ],
  exports: [
    CommonModule,
    MdMenuModule, MdToolbarModule, MdButtonModule, FlexLayoutModule,
    SecurityModule,
    MenuComponent],
  declarations: [MenuComponent],
  providers: []
})
export class MenuModule {

  static forRoot(options?: any): ModuleWithProviders {
    if (options && options.securityService) {
      return {
        ngModule: MenuModule,
        providers: [{
            provide: MenuService,
            useFactory: menuServiceFactory,
            deps: [options.securityService]
          }]
      }
    } else {
      return {
        ngModule: MenuModule,
        providers: [MenuService]
      };
    }
  }

  constructor (@Optional() @SkipSelf() parentModule: MenuModule) {
    if (parentModule) {
      throw new Error(
        'MenuModule is already loaded. Import it in the AppModule only');
    }
  }
 }

export function menuServiceFactory(_securityService: SecurityService): MenuService {
  return new MenuService(_securityService);
}

Solution

  • With @yurzui help - this is the refactored module -

    import { NgModule, ModuleWithProviders, SkipSelf, Optional } from '@angular/core';
    import { CommonModule } from '@angular/common';
    import { MenuComponent } from './menu.component';
    import { MenuService } from './menu.service';
    import { MdMenuModule, MdToolbarModule, MdButtonModule } from '@angular/material';
    import { FlexLayoutModule } from '@angular/flex-layout';
    import { SecurityModule, SecurityService } from '@savantly/ngx-security';
    
    @NgModule({
      imports: [
        CommonModule,
        MdMenuModule, MdToolbarModule, MdButtonModule, FlexLayoutModule, SecurityModule
      ],
      exports: [
        CommonModule,
        MdMenuModule, MdToolbarModule, MdButtonModule, FlexLayoutModule,
        SecurityModule,
        MenuComponent],
      declarations: [MenuComponent],
      providers: []
    })
    export class MenuModule {
    
      static forRoot({securityService = SecurityService}: {securityService?: SecurityService} = {}): ModuleWithProviders {
         return {
            ngModule: MenuModule,
            providers: [{
                provide: MenuService,
                useFactory: menuServiceFactory,
                deps: [securityService]
              }]
          };
      }
    
      constructor (@Optional() @SkipSelf() parentModule: MenuModule) {
        if (parentModule) {
          throw new Error(
            'MenuModule is already loaded. Import it in the AppModule only');
        }
      }
     }
    
    export function menuServiceFactory(_securityService: SecurityService): MenuService {
      return new MenuService(_securityService);
    }