Initiating Angular APP_INITIALIZERThe Angular APP_INITIALIZER

I am a newcomer to Angular and currently utilizing Angular6 for development purposes. I have a specific query regarding my app. Before the app initializes, I need to invoke three services that provide configurations required by the app. Let's refer to these services as Initialization, Config, and UserDetails. To facilitate this, I have included these services in the app-module.ts file as shown below.

`

    export function initializeApp(initService: InitializationService) {
        return () => initService.getInit();
    }

    export function fetchSettings(configService: ConfigService) {
        return () => configService.getConfig();
    }
export function retrieveUserSettings(userDetails: UserDetailsService) {
        return () => userDetails.getSettings();
    }

    @NgModule({
      imports: [/*my-imports*/],
      providers: [
        AppLoadService,
        { provide: APP_INITIALIZER, useFactory: initializeApp, deps: [InitializationService], multi: true },
        { provide: APP_INITIALIZER, useFactory: fetchSettings, deps: [ConfigService], multi: true },
        { provide: APP_INITIALIZER, useFactory: retrieveUserSettings, deps: [UserDetailsService], multi: true }
      ]
    })

` The InitializationService contains values necessary for the proper functioning of the other two services. The service requests are sent immediately during app initialization. I require the ConfigService and UserDetailsService to be invoked only after the InitializationService call is completed. To address this, I have implemented the following,

// AppConfig.ts

export class AppConfig {
  public static Config= {};

  public static $subject = new Subject();
}

// InitializationService

getInit () {

const promise = new Promise((resolve, reject) => {
      this.http.get().then(val => {
        AppConfig.config = val;
        AppConfig.$subject.next(val);
      });
};

return promise;
}

//ConfigService

getConfig () {
 if(AppConfig.Config.baseUrl === undefined) {
   AppConfig.$subject.subscribe(val => {
     this.http.get(AppConfig.Config.baseUrl).then(//doSomething);
   })
 }
}

A static subject is created and subscribed to in order to coordinate the sequence of calls. Once the InitializationService completes, it emits the next value for the subject, which is then observed by the ConfigService. Upon receiving the subscribed call, further operations are carried out. The same implementation is duplicated for the UserDetails getSettings() method.

Is my approach correct? Have you experimented with any other proven patterns?

Any suggestions or better approaches to handle the above scenario would be greatly appreciated.

Thank you in advance.

Best regards, hawx

Answer №1

Streamline the initialization process with a single initializer:

export function initializeAll(initService: InitializationService, configService: ConfigService, userDetails: UserDetailsService) {
  return () => {
    return initService.getInit().pipe(
      switchMap(() => {
        return flatMap([ConfigService.getConfig(), userDetails.getSettings()]);
      }),
    );
  }
}

Keep in mind that using flatMap assumes that both operations are completed before proceeding. This is just one way to handle it. With rxjs operators, you have complete control over the process and only need one APP_INITIALIZER.

Answer №2

//app-module code

export function initializeApplication(appInitializer:AppInitializer, configurationService:ConfigurationService) {
  // We return a promise as required by the app_init token. There is an ongoing issue with Angular regarding this: https://github.com/angular/angular/issues/15088
  return () => {
    const promise = new Promise((resolve, reject) => {
      appInitializer.load().then(() => {
        configurationService.fetch().then(() => {
          resolve();
        });
      });
    });
    return promise;
  }
}

//appInitializer.load() call

const promise = this.http.get<any>(`myConfigURL`).toPromise();
promise.then(response => {
 Object.assign(AppConfiguration.ENV, response.value.parameters);
});
return promise;

// configuration service call

const promise = this.http.get<any>(myConfigUrl).toPromise();
promise.then(response => {
  //process response data
});
return promise;

I opted for this approach to address the issue with managing Subject and due to time constraints preventing me from troubleshooting the Observable problems.

Thank you for your input.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Vue component prop values are not properly recognized by Typescript

Below is a Vue component I have created for a generic sidebar that can be used multiple times with different data: <template> <div> <h5>{{ title }}</h5> <div v-for="prop of data" :key="prop.id"> ...

Error: Vercel deployment of Next.Js app fails due to undefined localStorage

Encountering the issue ReferenceError: localStorage is not defined when attempting to deploy my Next.JS app on Vercel. const NewReserve: React.FC = () => { const setValue = (key: string, value: string) => { return localStorage.setItem(key, val ...

Altering or including new space variables within a custom Chakra-ui theme

Looking to customize spacing variables in a Chakra UI theme? I have successfully implemented various extensions, but changes to spacing are not being applied. const config: ThemeConfig = { initialColorMode: 'light', useSystemColorMode: false ...

Include a character in a tube using Angular

Hey everyone, I have a pipe that currently returns each word with the first letter uppercase and the rest lowercase. It also removes any non-English characters from the value. I'm trying to figure out how to add the ':' character so it will ...

The term 'App' is being referenced as a value when it is intended to be a type. Perhaps you meant 'typeof App'?

I am eager to master Typescript with React through hands-on experience, so I recently made the manual transition from JavaScript to TypeScript in my create-react-app. However, when working with my default testing file App.test.ts: import { render, screen ...

Unable to install vue-property-decorator

When attempting to set up Vue and TypeScript with class style using vue-property-decorator, I encountered a strange script after creating the project. I was anticipating a script like this: <script lang="ts"> import {Component, Vue} from & ...

Adding elements to a page while it is running can be achieved using a variety

Working on a college project, I am developing a demo web-app in Angular. The goal is to implement a feature where clicking a button adds a new node to the DOM tree. In JavaScript, a simple solution would be: document.getElementById('ticket-container& ...

Could routerLinkActive be used to substitute a class rather than simply appending one?

I have a navigation bar icon that links to an admin route. I want this icon to change its appearance when on that specific route. To achieve this, I can simply replace the mdi-settings-outline class with mdi-settings, displaying a filled version of the sam ...

The current inquiry does not conform to the MultipartHttpServletRequest format

I've been encountering an error while trying to send both an image and an object from Angular to Spring Boot. The error message I keep receiving is: Current request is not of type [org.springframework.web.multipart.MultipartHttpServletRequest] Below ...

Automatically select the unique item from the list with Angular Material AutoComplete

Our list of document numbers is completely unique, with no duplicates included. I am attempting to implement a feature in Angular Material that automatically selects the unique entry when it is copied and pasted. https://i.stack.imgur.com/70thi.png Curr ...

Error: Unable to locate the variable 'content' in the TypeScript code

Having an issue with my navigateToApp function. In the else condition, I am calling another function called openModalDialog(content). Unfortunately, I am encountering an error stating Cannot find name content. Can someone help me identify what is wrong h ...

Can an IonChange event be triggered from a component in Ionic 3?

Currently, I am working on developing an application that involves multiple forms. In most instances, when a user navigates back from the Confirmation view to the Form view to modify their entered data, it is essential for the form to retain the previously ...

Cloud Formation from CDK doesn't pause for addDependency to finish

I'm currently in the process of building a CDK stack and I am fairly new to CDK. My goal is to create a Simple Email Service (SES) ConfigurationSet followed by an EmailIdentity. The issue I encountered is that the creation of the EmailIdentity fails d ...

Is there a way to determine if a route, or any of its nested routes, are currently active

Consider the following route examples: <Routes> <Route path="admin"> <Route path="users"> <Route index element={<UserList />} /> <Route path="create" element={<UserDetails ...

What is the reason for requiring that the value type in a map must be uniform?

When using TypeScript, I expect the map type to be either a number or string, but unfortunately, an error is being reported. Click here for the Playground const map: Map<string, string | number> = new Map([ [ '1', &apo ...

After logging out, Next-auth redirects me straight back to the dashboard

In my NextJS application, I've implemented a credential-based authentication flow along with a dashboard page. To handle cases where an unauthorized user lands on the dashboard route, I've created a custom AccessDenied component. In the getServer ...

Guide to turning off the previous button in FullCalendar using Angular 7 and TypeScript

Can someone help me with disabling the previous button on FullCalendar if I go back 2 months? For example, if it's currently April and I navigate to February, I want the previous button to be disabled. I have FullCalendar implemented, but all the sol ...

What's the best way to implement satisfies with a generic type?

In my development process, I am working with components that have default values combined with props. To streamline this process, I created a single function for all components: export function getAssignProps <T extends {}>(propsMass:T[]){ return ...

Utilize an alias to define the SCSS path in an Angular-CLI library project

I am in the process of developing a library project using angular-cli. I have been following the guidelines outlined in the angular documentation. This has resulted in the creation of two main folders: one is located at ./root/src/app, where I can showcase ...

Demonstrating a feature in a custom Angular Material dialog box

I have a reusable custom Material UI Dialog that I want to utilize to show different components. For instance, I would like to display a Login component on one occasion and a Registration component on another. However, the issue arises when I assign my com ...