Mastering the Implementation of APP_INITIALIZER in Angular

I have an Angular 5.2.0 application and I wanted to implement the use of APP_INITIALIZER to load configuration data before the app starts. Below is a snippet from my app.module:

providers: [
    ConfigurationService,
    {
        provide: APP_INITIALIZER,
        useFactory: (configService: ConfigurationService) =>
            () => configService.loadConfigurationData(),
        deps: [ConfigurationService],
        multi: true
    }
],

Here is the code for my configuration.service:

import { Injectable, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { Configuration } from './configuration';

@Injectable()
export class ConfigurationService {
    private readonly configUrlPath: string = 'Home/Configuration';
    private configData: Configuration;

    constructor(
        private http: HttpClient,
        @Inject('BASE_URL') private originUrl: string) { }

    loadConfigurationData() {
        this.http
            .get<Configuration>(`${this.originUrl}${this.configUrlPath}`)
            .subscribe(result => {
                this.configData = {
                    test1ServiceUrl: result["test1ServiceUrl"],
                    test2ServiceUrl: result["test2ServiceUrl"]        
                }
            });
    }

    get config(): Configuration {
        return this.configData;
    }
}

Below is an example of how I'm using the configData in a component's constructor:

export class TestComponent {
    public test1ServiceUrl: string;

    constructor(public configService: ConfigurationService) {
        this.test1ServiceUrl = this.configService.config.test1ServiceUrl;
    }
}

While this implementation works well for components within the

<router-outlet></router-outlet>
, it fails for components outside of it. When debugging the constructor where it fails, I noticed that the configService was null. Why does the APP_INITIALIZER execute before the constructor of a component inside the
<router-outlet></router-outlet>
but not before the constructor of a component outside?

Answer №1

Thanks to the way APP_INITIALIZER operates, it is typical for asynchronous initializers to return promises. However, your configuration of APP_INITIALIZER multiprovider does not meet this standard because the loadConfigurationData function fails to return anything.

A correct implementation would resemble:

loadConfigurationData(): Promise<Configuration> {
  return this.http.get<Configuration>(`${this.originUrl}${this.configUrlPath}`)
  .do(result => {
    this.configData = result;
  })
  .toPromise();
}

Answer №2

Perform the following action

 function initiateStartupService(startupService: StartupService) {
      return () => startupService.load();
    }
    const APPINIT_PROVIDES = [
      StartupService,
      {
        provide: APP_INITIALIZER,
        useFactory: initiateStartupService,
        deps: [StartupService],
        multi: true,
      },
    ];

Beginning the startup service

load():Promise{
    return new Promise(resolve, reject){
        //load all your configuration 
         resolve(); 
    }

  }

Answer №3

Dealing with a comparable issue led me down the path of implementing a promise-based solution as well. Check out: ngOnInit starts before APP_INITIALIZER is done

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

What is the functionality and purpose of reselect's createStructuredSelector in a Typescript environment?

Can someone explain to me how the reselect method createStructuredSelector operates in Typescript? The code snippet I often come across is as follows: export interface SomeProps { readonly property1: string; readonly property2: boolean; readonly ...

The Angular 4 application is unable to proceed with the request due to lack of authorization

Hello, I am encountering an issue specifically when making a post request rather than a get request. The authorization for this particular request has been denied. Interestingly, this function works perfectly fine with my WPF APP and even on Postman. B ...

Typescript controller inheritance leading to Error: $injector:unpr Unknown Provider due to minification

LATEST UPDATE: 2019/07/16 The issue I am facing is actually a result of misusing $inject. Instead of declaring it as private $inject in api-service.ts, it should have been public static $inject = [...]. During the minification process, explicit injection ...

The type 'string' cannot be assigned to the type '"GET" | "get" | ...'

In my custom hook, I utilize the axios library for making requests: const useCustomHook = ({ endPoint = "", method = "GET", options = {} }) => { const [data, setData] = useState([]); const [request, setRequest] = useState<AxiosRequestConfig> ...

Typescript: The Art of Typing Functions

Hey there! I've been diving into learning typescript and have been working through some exercises. If you're curious, you can check out the exercise here. I'm a bit stuck on grasping how to approach this particular example. Here's the ...

Exploring the Comparison Between Angular RxJS Observables: Using takeUntil and unsubscribing via Subscription

When it comes to unsubscribing from observables in Angular components utilizing ngOnDestroy, there are multiple approaches available. Which of the following options is more preferable and why? Option 1: takeUntil The usage of RxJS takeUntil for unsubscri ...

Displaying data labels overlaid on top of data points in line charts

Currently, I am utilizing Angular2 along with ng2-charts to generate a line chart. My objective is to position the data labels directly above the points, similar to how they appear in the bar chart showcased in this image: bar chart I stumbled upon the ch ...

What is the best way to implement dotenv in a TypeScript project?

Attempting to load .env environment variables using Typescript. Here are my .env and app.ts files: //.env DB_URL=mongodb://127.0.0.1:27017/test // app.ts import * as dotenv from 'dotenv'; import express from 'express'; import mongoo ...

What could be causing the @RequestBody to receive an object with empty attributes?

I've encountered an issue with my springboot REST controller when handling PATCH and PUT requests. The fields/attributes for @RequestBody "company" are arriving as null values for some reason. Can anyone help me figure out what I might be missing? On ...

Using javascript to filter an array of JSON data

I'm contemplating how to streamline my filter code below. It's designed to filter out all JSON strings from a JSON array that contain specified values in one of three specific JSON string keys. My Visual Studio seems to be laughing at me, questio ...

Establishing navigation routes in a nested Angular 2 module through an NPM package

Currently, I am in the process of constructing an Angular 2 application and have established the following basic structure: AppModule AppComponent App.Routing App.template App.module In addition to this setup, I have ...

The react decorator for maintaining type safety fails to identify the appropriate ReturnType of the supplied function

I want to enhance the redux connect feature by using it as a decorator for a specific reducer/state. Although I know that redux connect can already be used as a decorator, I am curious about why my custom implementation does not work the way I expect. Her ...

Leverage the generic parameter type inferred from one function to dynamically type other functions

I am in the process of developing an API for displaying a schema graph. Here is a simplified version of what it entails: interface Node { name: string; } type NodeNames<T extends Node[]> = T[number]["name"]; // Union of all node names as strings ...

Developing Your Own Local Variable in Angular with Custom Structural Directive ngForIn

I am hoping for a clear understanding of this situation. To address the issue, I developed a custom ngForIn directive to extract the keys from an object. It functions correctly with the code provided below: import {Directive, Input, OnChanges, SimpleChan ...

Cookies are not being stored by the browser

I'm having an issue with storing a cookie sent from my Spring MVC backend at http://localhost:8080/ to my Angular frontend at http://localhost:4200. Even though I have configured CORS properly to allow credentials and specified the allowed origins, th ...

An unassigned variable automatically sets the disabled attribute to true on an input field

Is this behavior a problem or normal? Consider the following form structure: <form #form="ngForm" > <div> <label>field1</label> <input type="text" name="field1" [(ngModel)]="mainVar" [disabled]="someVar" /> ...

Calculating the total sum of values within a JSON array

Here is the data that I am working with: input1 = [{ "201609": 5, "201610": 7, "201611": 9, "201612": 10, "FY17": 24, "metric": "metric1", "careerLevelGroups": [{ "201609": 3, "201610": 6, "201611": ...

What is the process for converting TSX files into JSX format?

Recently, I completed a project using Expo and TypeScript due to my familiarity with type-safe languages. However, now I need to convert the code to Expo written in JavaScript. While I could manually remove the types as I work through it, I am curious if ...

Is there a way to successfully capture the mongodb error for jest testing purposes?

In order to create a user schema using mongoose, I have the following code: /src/server/models/User.ts: import { model, Schema } from "mongoose"; export const UserSchema = new Schema({ address: { type: String, }, email: { required: true, ...

The incorrect type is being assigned to an array of enum values in Typescript

Here's some code that I've been working on: enum AnimalId { Dog = 2, Cat = 3 } const animalIds: AnimalId[] = [AnimalId.Dog, 4]; I'm curious as to why TypeScript isn't flagging the assignment of 4 to type AnimalId[]. Shouldn't ...