0

I am using typescript map (testMap: Map<string, Array<string>> = new Map<string, Array<string>>();) in my angular application and everything works if I run it using 'ng serve'. But if run it using 'ng serve --aot', maps are not working. I don't get any exception but the maps are null when I debug my code. I want to know if it's a known issue and if there is a workaround for this. Thank you for your help.

//myLibrary

export class MyModule {
   static forRoot(config: MyConfig ): ModuleWithProviders {
    return {
      ngModule: MyModule,
      providers: [
          {provide: MY_CONFIG, useValue: config} 
      ]
    }
  }

}


export class MyConfig {
    myArray? :  string[];
    myMap?: Map<string, string[]>;

}

//user application

export const testMap: Map<string, string[]> = new Map<string, string[]>();
testMap.set("key1", ["value1", "value2"]);
testMap.set("key2", ["value3", "value4"]);


@NgModule({
  declarations: [
// some code
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    HttpClientModule,
    MyModule.forRoot({
        myArray: ["1234"],
        myMap: testMap,
      }
    ),
  ],
  providers: [
  ],
  bootstrap: [AppComponent]
})
export class AppModule {

}
user911
  • 1,509
  • 6
  • 26
  • 52

1 Answers1

2

The problem is that you cannot use anything that is not statically analyzable inside @NgModule if you want to build it with --aot
So you cannot call functions neither inside @NgModule nor in static forRoot method.
In order to create a Map it is necessary to call some functions (e.g. ctor, set).
You can replace Map with ordinary arrays and it will work.
Later on Map can be constructed from an array like this:

//...
export class MyConfig {
    myArray? :  string[];
    myMap?: [string, string[]][];

}
//...
export const testMap = [['test1', ['test1', 'test2']]]
//...
// setting up imports
MyModule.forRoot({
    myArray: ["1234"],
    myMap: testMap,
  }
),
//...
// config usage in your library
@Injectable()
export SomeService {
  private readonly myMap: Map<string, string[]>;
  constructor(@Inject(MY_CONFIG) config: MyConfig) {
    // converting from array to map
    this.myMap = new Map(config.myMap);
  }
}
Pavel Agarkov
  • 3,633
  • 22
  • 18
  • I didn't get how can I replace map with arrays? Could you please explain it with a code snippet. – user911 Aug 23 '18 at 17:48
  • I'm pretty sure I've provided various instances constructed in NgModule's file. You just need to assign them to variable and then use this variable in providers array. Like OP did with export const testMap. That said I don't know what is the problem here. – Tomasz Błachut Aug 24 '18 at 20:46
  • @TomaszBłachut can you please give me some code snippet to explain how to do it? – user911 Aug 25 '18 at 05:46
  • @TomaszBłachut I've tested both ways (inline and with const) and they don't work - map gets `undefined` when injected. For providers you can use factories but not for imports. – Pavel Agarkov Aug 25 '18 at 06:28
  • On second thought what I described is identical to injection of `MyConfig` instance. Would it mean that global JS class instances can't be handled by AOT? I find it hard to believe... – Tomasz Błachut Aug 25 '18 at 09:54
  • @TomaszBłachut, yes, you can construct a new instance of a class but directly in providers - not in imports. OP's problem also can be solved this way, but it would require a documentation for users to know what they need to specify in providers when this way they can see params of `forRoot` – Pavel Agarkov Aug 25 '18 at 10:36
  • @PavelAgarkov saying imports you mean that I can construct instance in `MyModule`'s file and create parameterless `forRoot` but can't pass it to `forRoot` from import location, is that correct? Gonna play with it latter because yet again when I thought I understood Angular DI it turns out I know nothing... – Tomasz Błachut Aug 25 '18 at 12:07
  • @TomaszBłachut, yes, that's correct. With providers you have more options. You even can use factories with injections like this: `{provide: SOME, useFactory: loadSome, deps: [Router, TransferState]}` – Pavel Agarkov Aug 25 '18 at 16:22