Angular function that returns a ModuleWithProviders and takes parameters into account

I am working on an application that consists of various components, each defining its own subset of route states. Depending on the context in which these components are used, a parent state needs to be provided under which some component states should be nested.

For example, here are the component states:

[{
  name: 'component',
  url: '/component',
  component: ComponentRootComponent,
  abstract: true,
  default: '.list'
}, {
  name: 'component.list',
  url: '',
  component: ComponentListComponent
},...]

In one specific section module of the app:

@NgModule({
  declarations: ...,
  imports: [
    UIRouterModule.forChild({ states: SECTION_STATES }),

    SomeComponentModule,
    UIRouterModule.forChild({
      states: RouterUtil.setParentState(SECTION_STATES[0].name, SOME_COMPONENT_STATES)
    })
  ]
})
export class AppSectionModule {}

The setParentState() function prefixes component states with the parent state name, ensuring they fall under that specific route state.

Instead of manually importing modules for each component, I want to create a single and configurable import function per component within my modules.

@NgModule({
  declarations: ...,
  imports: [
    UIRouterModule.forChild({ states: SECTION_STATES }),
    SomeComponentModule.importFor(SECTION_STATES[0].name)        
  ]
})
export class AppSectionModule {}

The importFor function should return a ModuleWithProviders type, wrapping the original component module and defining component routing under a specific parent route:

export class SomeComponentModule {
  public static importFor(parentState: string): ModuleWithProviders {
    return {
      ngModule: SomeComponentModule,
      providers: [
        // What should I do here?
      ]
    };
  }
}

How can I implement this function effectively? How do I incorporate UIRuterModule.forChild(...) within this function? These are the challenges I am currently faced with resolving.

Answer №1

To achieve this, you can utilize a "hidden" module.

The initial module contains a forRoot() method or in your scenario an importFor(), which references a hidden module.

When importFor is called, it invokes this hidden module, importing the original module and exporting it to maintain its hidden appearance.

This approach allows for the creation of reusable modules that can easily be integrated into projects with pre-configured reducers, effects, routes, and more :)

@NgModule({
  imports: [
    SharedModule,
  ],
  declarations: [
    ...SHARED_COMPONENTS,
  ],
  exports: [
    ...SHARED_COMPONENTS,
  ]
})
export class SecurityModule {

  // By importing SecurityModule.forRoot() in the app module, we actually import RootSecurityModule
  // This setup creates the IsAuthenticated guard and includes all feature elements like reducers, effects, and routes

  // To access shared components from SecurityModule later on, simply import the module without using forRoot()
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: RootSecurityModule, 
      providers: [
        IsAuthenticatedGuard,
      ],
    };
  }
}

@NgModule({
  imports: [

    // Import the above module to gain access to shared declarations
    SecurityModule,

    // Include the necessary security modules only once
    StoreModule.forFeature('security', securityReducer),
    EffectsModule.forFeature([
      SecurityEffects
    ]),
    SecurityRoutingModule,
  ],

  // Exporting SecurityModule is crucial for maintaining consistency when using SecurityModule.forRoot()
  exports: [
    SecurityModule,
  ]
})
export class RootSecurityModule {}

Answer №2

After examining the functionality of UIRouterModule, it appears to be functioning correctly according to expectations:

export class CustomComponentModule {
  public static initializeCustomState(parentState: string): ModuleWithProviders {
    return {
      ngModule: CustomComponentModule,
      providers: UIRouterModule.forChild({ states: RouterUtil.setParentState(parentState, CUSTOM_COMPONENT_STATES) }).providers
    };
  }
}

Now it is feasible to import the component module and configure its route states as demonstrated in the example below:

@NgModule({
  declarations: ...,
  imports: [
    UIRouterModule.forChild({ states: SECTION_STATES }),
    CustomComponentModule.initializeCustomState(SECTION_STATES[0].name)        
  ]
})
export class SectionModule {}

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

Can Node.js version 11 support node-sass in Angular projects?

I'm encountering a compilation error with my code. Could this be due to the node version? Does node-sass work with all versions of node? If not, how can I resolve this issue? Compilation error: Unable to locate module 'node-sass' ...

Tips for retrieving the angular route parameters from the URL?

I'm working with an Angular route that looks like this: /Chapter/:chapterId/Section/:sectionId. Let's say I have a URL such as: http://server.com/Chapter/1/Section/2?search=moby. Is there a way to extract the parameters and query string in Angu ...

Is it possible to access 'import.meta' only within a module in an Angular micro front-end setup?

I have been incorporating mfe (module federation microfrontend) into my Angular project. However, I encountered an error in the console when trying to load the remoteEntry.js file: import.meta outside a module The version of Angular that I'm using is ...

Using TypeScript to Load JSON Data from a Folder

I'm a newcomer to TypeScript and encountering an issue. My task involves dynamically loading objects from a directory that houses multiple JSON files. The file names are generated through an export bash script populating the resource directory. I wan ...

Showing container element only if certain condition is met but display the children in Angular 2+

I am looking to create a grid-style view for a list of Angular components, where I can display up to 4 components in each row. The question that comes close to what I need is the following: Angular 2 NgIf, dont render container element on condition but sh ...

Utilizing the map function to incorporate numerous elements into the state

I'm struggling with 2 buttons, Single Component and Multiple Component. Upon clicking Multiple Component, my expectation is for it to add 3 components, but instead, it only adds 1. import React, { useState, useEffect } from "react"; import ...

Steps for adding Node modules to a Nexus private repository

Running my organization's private Nexus npm repo, all packages are installed on my local machine through the internet. I want to store all packages on my Nexus private repo and have successfully uploaded them using the npm publish command. However, wh ...

"Unveiling the Intricacies of DOM Event Subscriptions with *ngIf

My preference is to handle DOM events as an observable stream, utilizing filter, concatMap, etc. similar to the example below. @Component({ template: `<button #btn>Submit<button`, selector: 'app-test', }) class TestComponent impleme ...

Storing user information in local storage with the Capacitor Storage Plugin: A Comprehensive Guide

I'm attempting to integrate Firebase Authentication into my Angular application. Here's the signUp() function within my AuthService: signUp(email: string, password: string, name: string) { const userCredential = from( firebase.auth(). ...

Retrieve the parent injector passed to the component during testing

My approach to obtaining an injector is as follows: constructor( private injector: Injector, ) {} Afterwards, I proceed to create a new injector and utilize the current one as its parent (specifically when opening a material dialog, though this detail ...

Is there a way to customize the slicing of *ngFor in a component according to the components it is being injected into?

This code snippet represents a component that needs to be included in other components: <div class="row"> <div class="col-12 [...]" *ngFor="let course of courses"> <div class="card"> ...

The Generic Function's Return Type in Typescript

The latest addition of ReturnType in TypeScript 2.8 is a highly valuable feature that enables you to capture the return type of a specific function. function foo(e: number): number { return e; } type fooReturn = ReturnType<typeof foo>; // numbe ...

Restricting the number of mat-chips in Angular and preventing the input from being disabled

Here is my recreation of a small portion of my project on StackBlitz. I am encountering 4 issues in this snippet: I aim to restrict the user to only one mat-chip. I attempted using [disabled]="selectedOption >=1", but I do not want to disable ...

The proxy configuration resulted in a 404 error

The URL to access my backend is http://localhost:80/something. In my package.json, I have the following line: "start": "ng serve --proxy-config proxyconfig.json". This is my proxyconfig.json file: { "/api": { "target": "http://localhost:80", " ...

What's the best way to ensure you're linting the correct file type for importing in Web

Upon installation of WebStorm, I encountered an issue when opening an existing Vue/TypeScript project. The IDE was not correctly importing and linting some file imports that were functioning properly through ESLint/webpack. In my usage of Vue 2.x with com ...

Tips for Ensuring the Observable Completes Before Subscribing

I utilized RXJS operators in my code to retrieve an array of locations. Here is the code snippet: return O$ = this.db.list(`UserPlaces/${this.authData.auth.auth.currentUser.uid}`, { query: { orderByChild: 'deleted', equalTo: fal ...

The MaxDuration feature for a 5-minute time limit is malfunctioning on the Serverless Pro Plan, resulting in a 504 ERROR on

I am currently using Next.js@latest with App Directory My application is hosted on Vercel I'm experiencing a 504 error from Vercel and I'm on the pro plan. My serverless functions are set to run for up to 5 minutes, but usually, they only take ...

HTTP POST request is being blocked due to cross-origin request

My angular client app is sending http requests to a .NET core web API, but I'm encountering a CORS error even though I have enabled CORS. Interestingly, GET requests to my SearchController work fine without any issues, but when it comes to sending a P ...

Angular2 Interactive Modal Pop Up

Here is an example of a modal in HTML code: <app-modal #modal1> <div class="app-modal-header"> header </div> <div class="app-modal-body"> You c ...

Angular 4/2: Exploring the Concept of Method Overloading

Currently, I am working on Angular 4 and have been struggling to find a suitable solution for method overloading in Angular 2 or 4. Can we actually implement method overloading in an Angular service class? I would really appreciate if someone could provide ...