1

In my application a config object that is being injected from the window to the Angular application. To go about this I had developed something along these lines:

Code

Model representing the config

export class AppConfig {
    constructor(
        public apiKey: string,
        public username: string,
        public languageCode: string
    ) { }
}

Creating an InjectionToken

import { InjectionToken } from '@angular/core';

import { AppConfig } from './shared';

export let APP_CONFIG = new InjectionToken<AppConfig>('appConfig');

This is then provided in the AppModule

import { APP_CONFIG } from './app-config-export';
....
@NgModule({
    ....
    { provide: APP_CONFIG, useValue: (window as any).appConfig }
})

export class AppModule { }

Finally inject it in a component

import { AppConfig } from '../shared';
import { APP_CONFIG} from './app-config-export';

....

export class AppComponent implements OnInit {
     constructor(
         @Inject(APP_CONFIG) private appConfig: any,
         private appService: AppService
     ) { }

     ngOnInit() {
         this.appService.initApp(this.appConfig);
     }
}

AOT Compilation

This works fine, however now I've been trying to build the application using AOT compilation. When I run the application with AOT, the appConfig is always null. I'm guessing it has something to do with the way I'm injecting the config which might not be compatible with AOT. Is there a way to get this to work with AOT?

I found this thread on github https://github.com/angular/angular/issues/19154, however I'm not understanding what is meant by "use a factory instead".

  • Angular: 4.4.4
  • Webpack: 3.8.1

Update

I've updated the AppModule like so:

import { APP_CONFIG } from './app-config-export';
....

export function appConfigFactory() {
    return (window as any).appConfig;
}

@NgModule({
    ....
    { provide: APP_CONFIG, useFactory: appConfigFactory() }
})

export class AppModule { }

Solution

I've updated the AppModule like so:

import { APP_CONFIG } from './app-config-export';
....

export function appConfigFactory() {
    return (window as any).appConfig;
}

@NgModule({
    ....
    { provide: APP_CONFIG, useFactory: appConfigFactory }
})

export class AppModule { }

I was calling the function in the useFactory callback instead of passing the function.

Daniel Grima
  • 2,765
  • 7
  • 34
  • 58

1 Answers1

1

@Pankaj Parkar's solution is almost correct, but you also need to export the useFactory callback to allow AoT:

import { APP_CONFIG } from './app-config-export';

export function configFactory() {
  return (window as any).appConfig;
}

@NgModule({
  providers: {
    provide: APP_CONFIG,
    useFactory: configFactory,
  }
})

Otherwise you will run into this error:

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

Martin Adámek
  • 16,771
  • 5
  • 45
  • 64
  • I was about to write the same thing :) I just tried the code, however the config is now `undefined` instead of `null` – Daniel Grima Oct 26 '17 at 21:56
  • Where/when do you set `window.appConfig`? Sounds like it is just not there when you need it. – Martin Adámek Oct 26 '17 at 21:58
  • The config is being set before the angular application is loaded. I'm debugging the code and when I type in `window.appConfig` in the console I do have a value. – Daniel Grima Oct 26 '17 at 22:01
  • Well testing this live via `console` is not a good idea, as you are doing it after the problem occurred. Try putting some `console.log()` to the place where you set the value and then to the place where you try to read it (in the factory). – Martin Adámek Oct 26 '17 at 22:02
  • Yep you're right, the code is not entering the factory. One weird thing I noticed is that looking at the code after AoT compilation the constructor in the AppComponent "removes" the `Inject()`, so instead of `@Inject(APP_CONFIG) private appConfig: any` I have `private appConfig: any` – Daniel Grima Oct 26 '17 at 22:07
  • Note sure if it's connected, but why do you have `any` type there? Why not use `AppConfig`? – Martin Adámek Oct 26 '17 at 22:26
  • 2
    Change ` useFactory: appConfigFactory()` ==> ` useFactory: appConfigFactory` – kemsky Oct 26 '17 at 22:35
  • 1
    lol didn't see that in the updated question! yeah, you have to pass that function reference, not its return value. – Martin Adámek Oct 26 '17 at 22:37
  • haha damn I didn't realise, I'm half asleep :D thanks for your help kemsky and Martin :) it's working :) – Daniel Grima Oct 26 '17 at 22:47