Seeking advice on navigation techniques between feature modules within Angular

During my work on a major angular project, I came across feature modules and routing modules which seemed to be great for organizing the project. However, when I implemented them, the app started malfunctioning. To address this issue, I decided to create a test project to experiment with routing between feature modules on a smaller scale.

Although the test project is functional, there are some minor issues that could potentially cause problems in the future and I would like to resolve them.

I have identified two main problems:

  1. The

    <a routerLink="some/link>
    directive does not work in feature modules but only in the app module. It appears as plaintext in the markup without creating a working link. I even tried importing routerLink into the feature modules module.ts file as a last resort, but it did not solve the issue.

  2. I had hoped that routing to a feature module would allow for different markup and styling based on the module being accessed - for example, routing to module-a would display one navigation menu while routing to module-b would show another. However, the default behavior persists where the app.component is displayed universally, and routing to a feature module simply replaces the specified component's URL in the router-outlet. I wish to disable this default behavior so that components routed to in one feature module have their own unique styles and features distinct from those routed to in another module, essentially having the router-outlet recognize that feature-a/component belongs to feature-a and therefore loads that module's HTML and CSS instead of the root app.component.

The source code for this test project, focused mainly on feature-a, has been provided below to avoid unnecessary clutter from feature-b.

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { FeatureAModule } from './feature-a/feature-a.module';
import { FeatureBModule } from './feature-b/feature-b.module';

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FeatureAModule,
    FeatureBModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

App.routing.ts


import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ChalpComponent } from './feature-a/chalp/chalp.component';
import { FeatureAComponent } from './feature-a/feature-a.component';
import { FeatureBComponent } from './feature-b/feature-b.component';
import { SkoneComponent } from './feature-b/skone/skone.component';


const routes: Routes = [
/*     { path: 'feature-a', component: FeatureAComponent,
        children: [
            { path : 'feature-a/chalp', component: ChalpComponent }
        ]
    },
    { path: 'feature-b', component: FeatureBComponent,
        children: [
            { path : 'feature-b/skone', component: SkoneComponent }
        ]
    }
 */    
    { path : 'feature-a/chalp', component: ChalpComponent },
    { path : 'feature-b/skone', component: SkoneComponent },
    { path: 'feature-a', component: FeatureAComponent },
    { path: 'feature-b', component: FeatureAComponent },
    
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Markup for app.component:


<h1>Inside App-Module now!</h1>

Go to feature A for chalp: <a routerLink="feature-a/chalp">Chalp</a>
Go to feature B for Skone: <a routerLink="feature-b/skone">Skone</a>
<router-outlet></router-outlet>

Feature-a routing + module file

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes, RouterOutlet, RouterLink } from '@angular/router';
import { FeatureAComponent } from './feature-a.component';
import { ChalpComponent } from './chalp/chalp.component';


const routes : Routes = [
    { path : '', component : FeatureAComponent },
    { path : 'chalp', component: ChalpComponent}
]


@NgModule({
  declarations: [ChalpComponent],
  imports: [
    CommonModule,
    RouterModule.forChild(routes)
  ]
})
export class FeatureAModule { }

Chalp - a component within feature-a

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-chalp',
  templateUrl: './chalp.component.html',
  styleUrls: ['./chalp.component.css']
})
export class ChalpComponent implements OnInit {

  constructor() { }

  ngOnInit(): void {
  }

}

Chalp markup

<p>Chalp works!</p>
<a routerLink="../">Go back one</a>

Answer №1

Here's a more efficient solution:

implement lazily loaded feature modules.

// main module routing:

router.forRoot([
  // following ng documentation recommendation
  { 
     path: 'admin',
     loadChildren: () => import('./items/items.module').then(m => m.ItemsModule)
  },
    where each distinct route prefix
    already exists in our large application.
    they are now stored and imported only when necessary,
    based on user demand.
    ...


])

//then in each feature modules' routing module
router.forChild([
    // consider first word as root to avoid redundant url like admin/admin!
    { path: '', component: AdminComponent,
      children: [
          /*All urls in the app with
           the 'admin' prefix*/ 
      ]
    }
]

From this journey into typescript, two key lessons learned:

  1. understand the framework thoroughly before utilizing it.
  2. in addition to handling imports and routing, feature modules also import a shared module named util, containing the core service module, all types and interfaces, components, pipes, and directives used throughout the app.

This understanding will aid in better application design going forward. The base app acts as the foundation for all feature modules integration and is bootstrapped during application launch. A cohesive structure is established for imports and exports, eliminating confusion about accessing services or interfaces.

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 process for executing Express's scaffold by utilizing "nodemon" and the basic "node" command instead of relying on the "npm start" command?

Could you help me locate where I need to make changes in my package.json file? Here is the content of my package.json: { "name": "xyz", "version": "0.0.0", "private": true, "scripts": { "start": "node ./bin/www" }, "dependencies": { ...

Ignoring page redirects in Node.JS

Directories are organized as follows: -public -landing -landing.html -Login -login.html -register -register.html -routes HTMLroutes APIroutes - server.js All commented code are attempts I have made without success if (bcry ...

Ways to resolve the issue of "await not waiting"

When I run an asynchronous function, I prefer to use the await declaration outside of the "then" method like this: const todayTotalVisitor = await getLastDayVisitors(); This way, the await keyword does not wait. async function calculateMonthTotal() { c ...

Using Cucumber for testing javascript-loaded content can be incredibly powerful and effective in ensuring the functionality

As I develop my Rails application, I've decided to incorporate a combination of Test Driven Development and Behavioral Driven Development into my process. The challenge arises as my app utilizes the MochaUI web application user interface framework, w ...

Issues with Chrome DevTools script blackboxing functionality not functioning as intended

Recently, I decided to explore the new feature in Chrome Devtools called "blackboxing a script". An informative article on script blackboxing functionality in Chrome Devtools Curious about the impact of blackboxing a script? Exceptions thrown from l ...

Trouble retrieving query parameters from a URL while trying to access URL parameters from a module

I am currently learning angular and facing a small problem that I'm unsure how to solve. My module looks like this: const hostHandler = setContext((operation: any, context: any) => ({ headers: { ...context?.headers, 'X-Location-Hostn ...

Creating an Angular library with a touch of Tailwind styling

Currently, I am working on a project using Angular14. Our goal is to create a library that can be published to our private repository in order to share the same look and feel across various (angular) applications. I have set up a basic application called ...

Incorporate commas into numerical values in jQuery counter using numeral.js

I currently have a counter on my page that counts from 0 to a specified number as the user scrolls. However, I am looking to add commas to the numbers displayed. For example, instead of 234235235, it should be shown as 234,235,235. After doing some resear ...

Inserting dates into a SQL platform

I am currently facing an issue where the date is being inserted into the SQL database as 30/12/1899. I am using Access 2003 for the database and cannot determine why this unexpected behavior is occurring! window.status='Loading contingency scripts - ...

How to update the state of a component in the root layout from its child components in Next JS 13 with the app router?

I am in the process of upgrading a Next JS app project to utilize the App Router. Within the layout.js (the root layout), there is a Logo component that will be visible on all routes. Within the RootLayout, I am managing a state variable to modify the ap ...

What is preventing me from using AJAX to input data into sqlite?

Implementing a local save feature in my Web App is proving to be quite challenging. Every time I attempt to send data in any form, I consistently encounter the following error: A builtins.TypeError occurs, followed by a stack trace in /SaveFile and jquery ...

Encountered a problem during the installation of firebase @angular/fire

I've been developing an Angular chat application and ran into some issues when trying to install Firebase using the command "npm install --save firebase @angular/fire". The installation resulted in a series of errors, with the main problem appearing t ...

The function res.send is unavailable and errors are not being properly managed

I encountered a peculiar error while using my function to create users in my mongoose database. Despite the user being successfully created, I am facing an issue where res.send is not functioning as expected, resulting in no response and instead, an error. ...

React displays an empty page when non-default routes are accessed in the build phase

<Router> <Switch> {console.log("Loading Routes")} <Route path="/booking" component={Booking} /> <Route path="/bookings" component={Bookings} /> <Route path=&quo ...

Showing different forms depending on the user's choice using ajax

My webpage features a <select> box for users to interact with. In order to proceed, the user must select an option from the dropdown menu. Once they make a selection, the <select> box should disappear using JavaScript (select.onchange(html.(di ...

Steps to bring life to your JavaScript counter animation

I need to slow down the counting of values in JavaScript from 0 to 100, so that it takes 3 seconds instead of happening instantly. Can anyone help me with this? <span><span id="counter"> </span> of 100 files</span> <s ...

Upon clicking a button on a JSP page, it triggers the ready function in JavaScript. This action may lead to

I have a button placed in my JSP file. <button id="btnViewAll">View All</button> Whenever this button is clicked, I expect the viewAllInventory() function in my JavaScript to be called. function viewAllInventory() { $.ajax({ url : "/Grad ...

How can the map function be executed sequentially every second, using async functions, fetch API, and promises, without running in parallel?

I am facing an issue with my map function, as it needs to fetch data from an online API that only allows one request per second. I attempted to solve this problem by implementing the following code: const sleep = (ms: number) => { return new Promise(( ...

Pause the execution of an AJAX callback function after numerous AJAX requests

I have two separate Ajax calls in my code. Both of them have different callbacks that need to execute upon successful call. $.ajax({ type: 'POST', url: "url1", success: foo1 }); $.ajax({ type: 'POST', url: "url2", ...

The code is throwing an error: Unable to access the 'grower' property as it is undefined

I'm facing an issue with a button that triggers the function 'SaveNewOpportunity' in my component file. When I click the button, I encounter the following error: ERROR TypeError: Cannot read property 'grower' of undefined Here is ...