Search code examples
angularangular-routingangular-routerlinkangular-router-params

Angular Dynamic path with param in the middle activate issue


Here is the issue, I have following paths:

const routes: Routes = [{
    path: '',
    component: UserComponent,
    children: [
      { path: "client/select/nodes", component: ClientSelectionComponent, canActivate: [MasterGuard], data: { guards: [GUARDS.AUTH] } },
      { path: "client/:clientID/nodes", component: ClientNodesComponent, canActivate: [MasterGuard], data: { guards: [GUARDS.AUTH] } },
    ]
}];

and

<a *ngFor="let item of navItems" [routerLink]="item.url" routerLinkActive="active-tab" [routerLinkActiveOptions]="{matrixParams:'ignored', paths:'subset', queryParams:'ignored', fragment:'ignored'}">{{item.name}}</a>

when clicked on client/select/nodes it adds active class to the a element. Because it's a real path exists in the nav-items and routerlinks know about it and this URL loads a client selection component which they select the client from the list and get navigated to /client/:clientID/nodes which actually loads the real page.

I still want the item of /client/select/nodes to get active class by ignoring the path parameter on routerLinkActive attribute.

I have achived this when I turn the URL to be /client/nodes/:clientID because comparing the subset makes sense. However this doesn't give me the feeling that this URL reflects the page intention. It looks like on this URL :clientID is actually a node id: /clients/nodes/1 for example.

I need a way to be able to ignore the path parameter when checking isActive for the URL, so doesn matter what write in between /clients and /nodes, it activates the button for /client/select/nodes.

The real code is much much more complex that this because whole navigation system is a complex component with it's own navItem type of objects and inner calls of itself for dropdown elements etc.

I tried to reduce it down to simplier question that just reflect what I mean and hardcoded answers will not work since the whole system works for dynamic navItem object.


Solution

  • After going over all the documentations and doing tons of search I ended up with such a custom solution as follows:

    Router Module

    const routes: Routes = [{
        path: '',
        component: UserComponent,
        children: [
          { path: "client/nodes", component: ClientSelectionComponent, canActivate: [MasterGuard], data: { guards: [GUARDS.AUTH] } },
          { path: "client/:clientID/nodes", component: ClientNodesComponent, canActivate: [MasterGuard], data: { guards: [GUARDS.AUTH] } },
        ]
    }];
    

    HTML

    <a *ngFor="let item of navItems"
    [routerLink]="item.url"
    routerLinkActive="active-tab"
    [routerLinkActiveOptions]="{matrixParams:'ignored', paths:'subset', queryParams:'ignored', fragment:'ignored'}"
    class.active-tab]="shouldCustomActivate(navItem)">{{item.name}}</a>
    

    TS

    let navItems = [
      {
        name: "Nodes",
        url: "/client/nodes",
        activateAsProxyRegex: "\/client\/[0-9]+\/nodes"
      },
      {
        name: "Lists",
        url: "/client/lists",
        activateAsProxyRegex: "\/client\/[0-9]+\/lists"
      }
    ]
    
    protected shouldCustomActivate(navItem: NavMenuItem): string {
      let proxyUrl = navItem.activateAsProxyRegex ? navItem.activateAsProxyRegex : '';
      if (proxyUrl === '')
        return "";
    
      if (!new RegExp(proxyUrl).test(this.router.url))
        return "";
    
      // this.emitChildSelected(true);
      return "active-tab";
    }