Muhammad Hamza
Muhammad Hamza

Reputation: 893

Dynamic routes being added to router but don't work

I have created an application in angular 6 which upon login takes the user to the main page. This page contains multiple links on both the navbar at the top (called toolbar) and the side bar on the left (called side-nav). I have created a custom dynamic routing service that would add links and their labels for the html templates.

The paths are added to the router using router.config.unshift, and I have verified that these paths are added properly under config when I log the router in the console.

The login page of my application has the root path (i.e ' ') and the Main page after login has the path /main (router configuration added below).

The problem I seem to be having has 2 parts:

  1. whenever I click a link on the side-nav or the toolbar, the url on the address bar shows me localhost.com:4200/main/<path> and the page displayed is the NotFoundComponent (i.e it could not find the route). I don't want the path to be a child of /main but the root url (i.e ' '), because the navigation bar would be on every page, and this might bring up a situation like localhost:4200/main/<path>/<anotherpath>/<someotherpath>/<path> on clicking multiple items, which a is pretty bad design.

  2. If i try to manually add the path to the application eg. localhost:4200/<path> the same result is shown (NotFoundComponent). No matter what I do it simply cannot find the path, even though in console it's perfectly defined when I log the router.

For testing purposes all my paths redirect me to a DummyComponent.

Here is my code, I am sharing the code for my ToolbarComponent, and the Side Nav is pretty much the same except for a few bits and pieces:

app.routing.ts:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';


import { LoginComponent } from 'src/app/views/login/login.component';
import { MainComponent } from 'src/app/views/main/main.component';
import { AuthGuardService } from 'src/app/services/auth-guard/auth-guard.service';
import { NotFoundComponent } from 'src/app/views/error/not-found/not-found.component';
/**
* Contains a list of routes to enable navigation from one view to the next
* as users perform application tasks
* @property {array} routes
*/
export const routes: Routes = [
  {
    path: '',
    component: LoginComponent,
  },
  {
    path: 'main',
    component: MainComponent,
    canActivate: [AuthGuardService]
  },
  {
    path: '**',
    component: NotFoundComponent
  }
];

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

dynamic-routing.service.ts

import { Injectable } from '@angular/core';
import { TranslatePipe } from 'src/app/pipes/translate/translate.pipe';

@Injectable({
  providedIn: 'root'
})
/*
* This service will provide components with the ability to dynamically create
* routes within the application
*/
export class DynamicRoutingService {

  /*
  * Array for storing links
  *
  */
  private links = new Array<{ text: string, path: string, icon: string }>();

  constructor(private translate: TranslatePipe) { }

  /*
  * Method to fetch data
  *
  */
  getLinks() {
    if (this.links.length != 0) {
      return this.links;
    }
    else {
      throw new Error(this.translate.transform("generic[responses][error][404][002]"));
    }
  }

  /*
  * Method to store data
  *
  */
  addItem({ text, path, icon = null }) {
    try {
      this.links.push({ text: text, path: path, icon: icon });
    } catch (e) {
      throw new Error(this.translate.transform("generic[responses][error][400]"));
    }
  }

  /*
  * Method to remove a specific link
  *
  */
  removeItem({ text }) {
    if (this.links.length != 0) {
      this.links.forEach((link, index) => {
        if (link.text === text) {
          this.links.splice(index, 1);
        }
      });
    } else {
      throw new Error (this.translate.transform('generic[resposnes][error][404][002]'));
    }
  }

  /*
  * Remove all links from the array
  */
  clearAll() {
    this.links.length = 0;
  }
}

toolbar.component.ts

import { Component, OnInit } from '@angular/core';
import { TranslatePipe } from 'src/app/pipes/translate/translate.pipe';
import { DynamicRoutingService } from 'src/app/services/dynamic-routing/dynamic-routing.service';
import { Router } from '@angular/router';
import { DummyComponent } from 'src/app/views/dummy/dummy.component';

@Component({
  selector: 'app-toolbar',
  templateUrl: './toolbar.component.html',
  styleUrls: ['./toolbar.component.scss'],
  providers: [DynamicRoutingService]
})

/**
* This component renders the Toolbar UI
*
*/
export class ToolbarComponent implements OnInit {

  /**
  * Object containing the translated names and their respective icons
  * @property {array} links
  */
  links: Array<{ text: string, path: string }>;

  /**
  * constructor for toolbar component is responsible for initializing translatePipe, dynamic routing and router,
  * as well as adding routes dynamically to the router and the dynamicRouting service
  * @param translate
  * @param router
  * @param dynamicRouting
  *
  */
  constructor(private translate: TranslatePipe, private router: Router, private dynamicRouting: DynamicRoutingService) {
    this.router.config.unshift(
      { path: 'knowledge-base', component: DummyComponent },
      { path: 'home', component: DummyComponent },
      { path: 'settings', component: DummyComponent }
    );
    this.dynamicRouting.addItem({ text: "home", path: "home" });
    this.dynamicRouting.addItem({ text: "knowledge_base", path: "knowledge-base" });
    this.dynamicRouting.addItem({ text: "settings", path: "settings" });
  }

  /**
  * Upon initialization this function fetches the links and inserts the translated
  * text and path to be used by the template
  *
  * @param
  * @return
  */
  ngOnInit() {
    this.links = [];
    let rawData = this.dynamicRouting.getLinks();
    let self = this;
    rawData.forEach(function(data) {
      let text = self.translate.transform("generic[toolbar][categories][" + data.text + "][label]");
      self.links.push({ text: text, path: data.path });
    });
  }

}

toolbar.component.html

<app-header
  [fixed]="true"
  [navbarBrandFull]="{src: 'assets/logo.png', width: 143, height: 36, alt: 'RT Logo'}"
  [navbarBrandMinimized]="{src: 'assets/logo2.png', width: 35, height: 35, alt: 'RT Logo'}"
  [sidebarToggler]="'lg'">
  <ul class="nav navbar-nav d-md-down-none" routerLinkActive="active">
    <li class="nav-item px-3" *ngFor="let link of links">
      <a class="nav-link" [routerLink]="link.path">{{ link.text }}</a>
    </li>
  </ul>
  <ul class="nav navbar-nav ml-auto">
  </ul>
</app-header>

Upvotes: 2

Views: 842

Answers (1)

Muhammad Hamza
Muhammad Hamza

Reputation: 893

Solved: The problem lied in my template: the value passed to routerLink needed to be modified, example here and solution here

Upvotes: 2

Related Questions