2

In my angular application i m setting provideAppInitializer to get config from service and then provideMatomo(loadMatomoConfig)) tries to load the config which set by provideAppInitializer(intializeAppFn)

    export const appConfig: ApplicationConfig = {
      
      providers: [
        ...
        provideAppInitializer(intializeAppFn),
        provideMatomo(loadMatomoConfig))
        ..
      ]
    };
    
    const intializeAppFn = async () => {
      try {
        const configService = inject(AppConfigService);
        await configService.loadConfig();
        return true
      }catch (error) {  
        throw error;
      }
      
    };

const  loadMatomoConfig =  ():MatomoConfiguration => {
     const c = inject(AppConfigService)
     console.log('config',c.getConfig()) //this always null
    
}

AppConfigService.ts

export class AppConfigService {

  private config: AppConfig | null = null;

  constructor(private http: HttpClient) { }

  async loadConfig(): Promise<void> {
    try {
      const response = await lastValueFrom(
        this.http.get('/config/app-config.json')
      );
       this.config = response as AppConfig;
    } catch (error) {
      console.error('Failed to load configuration', error);
      throw error;
    }
  }

  getConfig(): AppConfig {
    if (!this.config) {
      throw new Error('Configuration not loaded. Ensure APP_INITIALIZER has completed.');
    }
    return this.config;
  }
}

the config setting properly in the first provideAppInitializer(intializeAppFn) ,but when try to get in the loadMatomoConfig (c.getConfig() is always null) its always getting null

1 Answer 1

0

Modify your service, so that config has default values, then we set the inner values from loadConfig, but we do not change the memory reference of the config property.

By doing so, the values are applied to the provider without hassle and the library should pickup the changes.

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

  private config: AppConfig | null = {
    siteId: '',
    trackerUrl: '',
  };

  constructor(private http: HttpClient) { }

  async loadConfig(): Promise<void> {
    try {
      const response = await lastValueFrom(
        this.http.get('/config/app-config.json')
      );
       this.config.siteId = response.siteId;
       this.config.trackerUrl = response.trackerUrl;
    } catch (error) {
      console.error('Failed to load configuration', error);
      throw error;
    }
  }

  getConfig(): AppConfig {
    if (!this.config.trackerUrl) {
      throw new Error('Configuration not loaded. Ensure APP_INITIALIZER has completed.');
    }
    return this.config;
  }
}

Now we fetch the values on the app initializer, by calling loadConfig, we can directly return this, since the app initializer can resolve the returned promise.

const initializeMatomoFn = () => {
  const configService = inject(AppConfigService);
  return configService.loadConfig();
};

Full Code:

import {
  Component,
  inject,
  Injectable,
  provideAppInitializer,
} from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { provideHttpClient } from '@angular/common/http';
import { provideMatomo, withRouter } from 'ngx-matomo-client';
import { of, delay, firstValueFrom } from 'rxjs';
import { JsonPipe } from '@angular/common';
@Injectable({
  providedIn: 'root',
})
export class AppConfigService {
  config = {
    siteId: '',
    trackerUrl: '',
  };

  loadConfig() {
    console.log('initializer');
    return firstValueFrom(
      of({
        siteId: 'test',
        trackerUrl: 'https://google.com',
      }).pipe(delay(2000))
    ); // simulate API
  }
}
const initializeMatomoFn = () => {
  const configService = inject(AppConfigService);
  return configService.loadConfig().then((config: any) => {
    configService.config.siteId = config.siteId;
    configService.config.trackerUrl = config.trackerUrl;
    return true;
  });
};

@Component({
  selector: 'app-root',
  imports: [JsonPipe],
  template: `{{appConfigService.config | json}}`,
})
export class App {
  appConfigService = inject(AppConfigService);
  name = 'Angular';
}

bootstrapApplication(App, {
  providers: [
    provideHttpClient(),
    provideAppInitializer(initializeMatomoFn),
    provideMatomo(() => {
      console.log('matomoto');
      const configService = inject(AppConfigService);
      console.log(configService.config);
      return configService.config;
    }, withRouter()),
  ],
});

Stackblitz Demo

Sign up to request clarification or add additional context in comments.

5 Comments

Muarali i can see both values {siteId: 1, trackerUrl: ''}siteId: 1trackerUrl: "localhost:8088"[[Prototype]]: Object but how do i get the latest value
@shamonshamsudeen please place debugger on this.config.trackerUrl = response.trackerUrl; and check why the URL is not set correctly. you might be assigning an object instead of a string
the assignments are correct
@shamonshamsudeen then why the object you shared looks incorrect? It's a simple assignment right?
@shamonshamsudeen please do not refer the stackblitz, but the code snippets alone

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.