Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use dynamic configuration in AzureMapsModule.forRoot() #35

Closed
ddlaat opened this issue Apr 22, 2021 · 6 comments
Closed

Use dynamic configuration in AzureMapsModule.forRoot() #35

ddlaat opened this issue Apr 22, 2021 · 6 comments
Assignees
Labels
enhancement New feature or request

Comments

@ddlaat
Copy link

ddlaat commented Apr 22, 2021

Hello,

I'm trying to load ng-azure-maps with data that comes from a settings API. So my subscriptionKey is different per environment, and not static.

I already know it's impossible to have a service injected into the imports part of the @NgModule decorator. But I would think it's possible to have a provider which overrides the AZUREMAPS_CONFIG InjectionToken.

import { AZUREMAPS_CONFIG } from 'ng-azure-maps/lib/configuration';

...

providers: [
  {
      provide: AZUREMAPS_CONFIG,
      useValue: {
          authOptions: {
              authType: AuthenticationType.subscriptionKey,
              subscriptionKey: 'TEST'
          }
      }
  }
]

Now I'm facing the error:

Module not found: Error: Can't resolve 'ng-azure-maps/lib/configuration' in 'C:\MyProject\ClientApp\src\app'

Am I on the right track? Or is there another way to do this?

@arnaudleclerc
Copy link
Owner

Hi,

The AZUREMAPS_CONFIG injection token is currently not exported by the library, that's why you have this error. I will in any case change that so you can use override it on the providers declaration Something like that would then work :

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { AzureMapsModule, AZUREMAPS_CONFIG } from 'ng-azure-maps';
import { environment } from '../environments/environment';
import { AuthenticationType } from 'azure-maps-control';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AzureMapsModule.forRoot({
      authOptions: environment.authOptions
    })
  ],
  providers: [
    {
      provide: AZUREMAPS_CONFIG,
      useValue: {
        authOptions: {
          authType: AuthenticationType.subscriptionKey,
          subscriptionKey: '<your-subscription-key>'
        }
      }
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

But I am not sure this would allow you to set the key from your API. Maybe what you actually need here is an APP_INITIALIZER which calls you API to retrieve the subscription key and set it on the configuration of the library ? Something like that :

import { BrowserModule } from '@angular/platform-browser';
import { APP_INITIALIZER, NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { AzureMapsModule, setAtlasConfiguration } from 'ng-azure-maps';
import { HttpClient } from '@angular/common/http';
import { AuthenticationType } from 'azure-maps-control';

function setAuthentication(httpClient: HttpClient): () => Promise<void> {
  console.log('setAuthentication');
  return (): Promise<void> => {
    return new Promise<void>((resolve, reject) => {
      httpClient.get<{ subscriptionKey: string }>('http://localhost:7071/api/GetAuth').subscribe(auth => {
        console.log(auth.subscriptionKey);
        setAtlasConfiguration({
          authOptions: {
            authType: AuthenticationType.subscriptionKey,
            subscriptionKey: auth.subscriptionKey
          }
        });
        resolve();
      }, error => {
        reject(error);
      });
    });
  };
}

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AzureMapsModule.forRoot(),
  ],
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: setAuthentication,
      deps: [HttpClient],
      multi: true
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

@arnaudleclerc
Copy link
Owner

Both are in any case valid use cases that I would add to the library. None would currently work as neither AZUREMAPS_CONFIGURATION or setAtlasConfiguration are currently exported. I will try to add that today and let you know when this is done

@ddlaat
Copy link
Author

ddlaat commented Apr 22, 2021

Thank you for your quick reply! That would be great!
I simplified my example a bit, but actually I also had a factory which depends on a service which is loaded from the main whenever my Angular application starts:

main.ts

AppSettingsService.loadConfig().then(() => {
  return platformBrowserDynamic().bootstrapModule(AppModule);
})

.loadConfig() holds pretty much the same code as in your proposal, with a HttpClient.

app.module.ts

providers: [
  {
      provide: AZUREMAPS_CONFIG,
      deps: [AppSettingsService],
      useFactory: (appSettingsService: AppSettingsService) => {
          return appSettingsService.getConfig().azureMapsSubscriptionKey;
      }
  }
]

I'm looking forward to the code change!

@arnaudleclerc
Copy link
Owner

arnaudleclerc commented Apr 22, 2021

I just published a version 3.6.0-alpha.4 with those changes. It should now be possible to import AZUREMAPS_CONFIGURATION directly from ng-azure-maps. The call to AzureMapsModule.forRoot is still necessary to create the injection token, but you do not need to pass any parameter to the method anymore. In your case, it would look like that :

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

import { AzureMapsModule, AZUREMAPS_CONFIG } from 'ng-azure-maps';

...

@NgModule({
  ...
  imports: [
    AzureMapsModule.forRoot()
  ],
  providers: [
    {
      provide: AZUREMAPS_CONFIG,
      deps: [AppSettingsService],
      useFactory: (appSettingsService: AppSettingsService) => {
          return appSettingsService.getConfig().azureMapsSubscriptionKey;
      }
     }
  ]
})
export class AppModule { }

If at some point you want to use the APP_INITIALIZER, you would need to call setAzureMapsConfiguration to set the configuration. I renamed it from setAtlasConfiguration for clarity.

Would you mind trying this version and letting me know if this works for you ? If so, I will publish a stable version later this day.

@arnaudleclerc arnaudleclerc self-assigned this Apr 22, 2021
@arnaudleclerc arnaudleclerc added the enhancement New feature or request label Apr 22, 2021
@ddlaat
Copy link
Author

ddlaat commented Apr 22, 2021

I've tested it, it works perfectly! Thank you very much for adding this valuable piece of functionality!

@arnaudleclerc
Copy link
Owner

Great, thanks for the feedback and for the feature request! I have just published a stable version 3.6.0. I will close this issue, feel free to reopen it if necessary!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants