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

Load initial configuration async? #31

Closed
csgulyas opened this issue Mar 7, 2022 · 7 comments
Closed

Load initial configuration async? #31

csgulyas opened this issue Mar 7, 2022 · 7 comments

Comments

@csgulyas
Copy link

csgulyas commented Mar 7, 2022

Is it currently possible to load the Site ID and Tracker URL in an async manner?

I have an Angular 10 project that stores every config in a database, and would need to query the backend before I can start setting up Matomo.

I looked at the docs and was hopeful maybe via provider useFactory I could return a Promise, but doesn't look doable.

@EmmanuelRoux
Copy link
Owner

EmmanuelRoux commented Mar 7, 2022

Hi @csgulyas, this seems to be an Angular issue, not a ngx-matomo issue.

And you're right, Angular does not have such a feature currently (see Angular feature request: angular/angular#23279)

Have you tried using APP_INITIALIZER? That may be a viable workaround.

@EmmanuelRoux
Copy link
Owner

EmmanuelRoux commented Mar 7, 2022

You may end up with something like this:

@Injectable({ providedIn: 'root' })
export class MatomoConfigService {

  myBackendConfig: any;

  async preload(): Promise<void> {
    this.myBackendConfig = await ......; // http call
  }

  buildConfig(): MatomoConfiguration {
    return {
      siteId: this.myBackendConfig.siteId,
      // ...
    };
  }
}

export function initializeMatomoFactory(service: MatomoConfigService) {
  return () => service.preload();
}

export function matomoConfigFactory(service: MatomoConfigService) {
  return service.buildConfig();
}

@NgModule({
  // ...
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: initializeMatomoFactory,
      deps: [MatomoConfigService],
      multi: true
    },
    {
      provide: MATOMO_CONFIGURATION,
      useFactory: matomoConfigFactory,
      deps: [MatomoConfigService]
    }
  ]
})
export class AppModule {}

@csgulyas
Copy link
Author

Thanks for your fast response. I tried your suggestion, but I don't think that approach is doable. After reading about APP_INITIALIZER and fiddling around with it a bit, I learned that it only delays the app start (if a promise needs to be resolved), but other providers don't wait for anything.

I've made a minimal repo in case I was doing something wrong: https://github.com/csgulyas/matomotest.

The MATOMO_CONFIGURATION expects the config to be available immediately. If I leave the myBackendConfig uninitialized, or otherwise in an invalid state, the tracker logic throws and complains about null values.

@EmmanuelRoux
Copy link
Owner

Oh yes you're right, factory providers don't wait for APP_INITIALIZER to be resolved...
Again, this is a general issue with Angular, not this lib... There's not much we can do for that...

But, an alternative is see, would be load load your backend config yourself before you start Angular.

First declare a config type + injection token:

export class MyBackendConfig {
  // ...
}

const MY_BACKEND_CONFIG = new InjectionToken<MyBackendConfig>('My Backend Configuration');

Then in main.ts file, wrap the bootstrap process in a fetch call to get your config, then add a provider for the config as an argument to platformBrowserDynamic() call:

// main.ts
fetch('/my-backend-config.json')
  .then(response => response.json())
  .then((config: MyBackendConfig) => {
    // Here include the classic bootstrap process
    
    if (environment.production) {
      enableProdMode();
    }

    // Just add a provider for the config as an argument to platformBrowserDynamic() call:
    platformBrowserDynamic([
      { provide: MY_BACKEND_CONFIG, useValue: config },
    ])
      .bootstrapModule(AppModule)
      .catch(err => console.error(err));
  });

Finally, you can declare your matomo config factory using MY_BACKEND_CONFIG as a dependency:

// app.module.ts
export function matomoConfigFactory(myBackendConfig: MyBackendConfig) {
  return {
      siteId: myBackendConfig.siteId,
      trackerUrl: myBackendConfig.trackerUrl,
      // ...
    };
}

@NgModule({
  // ...
  providers: [
    {
      provide: MATOMO_CONFIGURATION,
      useFactory: matomoConfigFactory,
      deps: [MY_BACKEND_CONFIG]
    }
  ]
})
export class AppModule {}

Drawback is you can't use here anything defined in your app (such as other providers, etc...)

@csgulyas
Copy link
Author

Appreciate your help. Very interesting approach.

EmmanuelRoux added a commit that referenced this issue Jul 22, 2022
github-actions bot pushed a commit that referenced this issue Jul 22, 2022
# [2.5.0](v2.4.2...v2.5.0) (2022-07-22)

### Bug Fixes

* **tracker:** prevent initializing Matomo more than once ([8b1e773](8b1e773))

### Code Refactoring

* **tracker:** replace init() method with initialized() for naming consistency ([30c415d](30c415d))

### Features

* **tracker:** allow deferred trackers configuration ([77a377f](77a377f)), closes [#31](#31) [#54](#54)

### Deprecations

* **tracker:** Method `MatomoInitializerService.init()` has been deprecated.
Use `MatomoInitializerService.initialize()` instead.
@EmmanuelRoux
Copy link
Owner

🎉 This issue has been resolved in version 2.5.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

EmmanuelRoux added a commit that referenced this issue Jul 22, 2022
github-actions bot pushed a commit that referenced this issue Jul 22, 2022
# [3.1.0](v3.0.0...v3.1.0) (2022-07-22)

### Bug Fixes

* **tracker:** prevent initializing Matomo more than once ([784b1de](784b1de))

### Code Refactoring

* **tracker:** replace init() method with initialized() for naming consistency ([8e23baf](8e23baf))

### Features

* **tracker:** allow deferred trackers configuration ([cd51156](cd51156)), closes [#31](#31) [#54](#54)

### Deprecations

* **tracker:** Method `MatomoInitializerService.init()` has been deprecated.
Use `MatomoInitializerService.initialize()` instead.
@EmmanuelRoux
Copy link
Owner

🎉 This issue has been resolved in version 3.1.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants