Angel Bonilla
Angel Bonilla

Reputation: 11

Angular child routes (lazy loaded into AppRoutingModule) data is always an empty object ({}). Trying to access it from route guard

I've been struggling with this issue for a week or so but everything I've found online (and tried) is not helping.

I have an AngularJS project (Angular v11) with the following structure:

src/app
├── app.component.ts
├── app.module.ts
├── app-routing.module.ts
├── dashboard
│   ├── campaign
│   │   ├── campaign.component.html
│   │   ├── campaign.component.scss
│   │   ├── campaign.component.spec.ts
│   │   ├── campaign.component.ts
│   │   ├── campaign-form
│   │   │   ├── campaign-form.component.html
│   │   │   ├── campaign-form.component.scss
│   │   │   ├── campaign-form.component.spec.ts
│   │   │   └── campaign-form.component.ts
│   │   ├── campaign-list
│   │   │   ├── campaign-list.component.html
│   │   │   ├── campaign-list.component.scss
│   │   │   ├── campaign-list.component.spec.ts
│   │   │   └── campaign-list.component.ts
│   │   └── campaign-show
│   │       ├── campaign-show.component.html
│   │       ├── campaign-show.component.scss
│   │       ├── campaign-show.component.spec.ts
│   │       └── campaign-show.component.ts
│   ├── channel
│   │   ├── channel.component.html
│   │   ├── channel.component.scss
│   │   ├── channel.component.spec.ts
│   │   ├── channel.component.ts
│   │   ├── channel-form
│   │   │   ├── channel-form.component.html
│   │   │   ├── channel-form.component.scss
│   │   │   ├── channel-form.component.spec.ts
│   │   │   └── channel-form.component.ts
│   │   ├── channel-list
│   │   │   ├── channel-list.component.html
│   │   │   ├── channel-list.component.scss
│   │   │   ├── channel-list.component.spec.ts
│   │   │   └── channel-list.component.ts
│   │   └── channel-show
│   │       ├── channel-show.component.html
│   │       ├── channel-show.component.scss
│   │       ├── channel-show.component.spec.ts
│   │       └── channel-show.component.ts
│   ├── contract
│   │   ├── contract.component.html
│   │   ├── contract.component.scss
│   │   ├── contract.component.spec.ts
│   │   ├── contract.component.ts
│   │   └── contract-list
│   │       ├── contract-list.component.html
│   │       ├── contract-list.component.scss
│   │       ├── contract-list.component.spec.ts
│   │       └── contract-list.component.ts
│   ├── dashboard.component.html
│   ├── dashboard.component.scss
│   ├── dashboard.component.ts
│   ├── dashboard.module.ts
│   ├── dashboard-routing.module.ts
│   ├── invoice
│   │   ├── invoice.component.html
│   │   ├── invoice.component.scss
│   │   ├── invoice.component.spec.ts
│   │   ├── invoice.component.ts
│   │   ├── invoice-form
│   │   │   ├── invoice-form.component.html
│   │   │   ├── invoice-form.component.scss
│   │   │   ├── invoice-form.component.spec.ts
│   │   │   └── invoice-form.component.ts
│   │   └── invoice-list
│   │       ├── invoice-list.component.html
│   │       ├── invoice-list.component.scss
│   │       ├── invoice-list.component.spec.ts
│   │       └── invoice-list.component.ts
│   ├── lead
│   │   ├── lead.component.html
│   │   ├── lead.component.scss
│   │   ├── lead.component.spec.ts
│   │   ├── lead.component.ts
│   │   ├── lead-form
│   │   │   ├── lead-form.component.html
│   │   │   ├── lead-form.component.scss
│   │   │   ├── lead-form.component.spec.ts
│   │   │   └── lead-form.component.ts
│   │   ├── lead-list
│   │   │   ├── lead-list.component.html
│   │   │   ├── lead-list.component.scss
│   │   │   ├── lead-list.component.spec.ts
│   │   │   └── lead-list.component.ts
│   │   └── lead-show
│   │       ├── lead-show.component.html
│   │       ├── lead-show.component.scss
│   │       ├── lead-show.component.spec.ts
│   │       └── lead-show.component.ts
│   ├── marketer
│   │   ├── marketer.component.html
│   │   ├── marketer.component.scss
│   │   ├── marketer.component.spec.ts
│   │   ├── marketer.component.ts
│   │   ├── marketer-form
│   │   │   ├── marketer-form.component.html
│   │   │   ├── marketer-form.component.scss
│   │   │   ├── marketer-form.component.spec.ts
│   │   │   └── marketer-form.component.ts
│   │   └── marketer-list
│   │       ├── marketer-list.component.html
│   │       ├── marketer-list.component.scss
│   │       ├── marketer-list.component.spec.ts
│   │       └── marketer-list.component.ts
│   ├── opportunity
│   │   ├── opportunity.component.html
│   │   ├── opportunity.component.scss
│   │   ├── opportunity.component.spec.ts
│   │   ├── opportunity.component.ts
│   │   ├── opportunity-form
│   │   │   ├── opportunity-form.component.html
│   │   │   ├── opportunity-form.component.scss
│   │   │   ├── opportunity-form.component.spec.ts
│   │   │   └── opportunity-form.component.ts
│   │   ├── opportunity-list
│   │   │   ├── opportunity-list.component.html
│   │   │   ├── opportunity-list.component.scss
│   │   │   ├── opportunity-list.component.spec.ts
│   │   │   └── opportunity-list.component.ts
│   │   └── opportunity-show
│   │       ├── opportunity-show.component.html
│   │       ├── opportunity-show.component.scss
│   │       ├── opportunity-show.component.spec.ts
│   │       └── opportunity-show.component.ts
│   ├── product
│   │   ├── product.component.html
│   │   ├── product.component.scss
│   │   ├── product.component.spec.ts
│   │   ├── product.component.ts
│   │   ├── product-form
│   │   │   ├── product-form.component.html
│   │   │   ├── product-form.component.scss
│   │   │   ├── product-form.component.spec.ts
│   │   │   └── product-form.component.ts
│   │   ├── product-list
│   │   │   ├── product-list.component.html
│   │   │   ├── product-list.component.scss
│   │   │   ├── product-list.component.spec.ts
│   │   │   └── product-list.component.ts
│   │   └── product-show
│   │       ├── product-show.component.html
│   │       ├── product-show.component.scss
│   │       ├── product-show.component.spec.ts
│   │       └── product-show.component.ts
│   ├── profile
│   │   ├── profile.component.html
│   │   ├── profile.component.scss
│   │   ├── profile.component.spec.ts
│   │   ├── profile.component.ts
│   │   ├── profile-form
│   │   │   ├── profile-form.component.html
│   │   │   ├── profile-form.component.scss
│   │   │   ├── profile-form.component.spec.ts
│   │   │   └── profile-form.component.ts
│   │   ├── profile-list
│   │   │   ├── profile-list.component.html
│   │   │   ├── profile-list.component.scss
│   │   │   ├── profile-list.component.spec.ts
│   │   │   └── profile-list.component.ts
│   │   └── profile-show
│   │       ├── profile-show.component.html
│   │       ├── profile-show.component.scss
│   │       ├── profile-show.component.spec.ts
│   │       └── profile-show.component.ts
│   └── service
│       ├── service.component.html
│       ├── service.component.scss
│       ├── service.component.spec.ts
│       ├── service.component.ts
│       ├── service-form
│       │   ├── service-form.component.html
│       │   ├── service-form.component.scss
│       │   ├── service-form.component.spec.ts
│       │   └── service-form.component.ts
│       ├── service-list
│       │   ├── service-list.component.html
│       │   ├── service-list.component.scss
│       │   ├── service-list.component.spec.ts
│       │   └── service-list.component.ts
│       └── service-show
│           ├── service-show.component.html
│           ├── service-show.component.scss
│           ├── service-show.component.spec.ts
│           └── service-show.component.ts
└── login
    ├── login.component.html
    ├── login.component.scss
    ├── login.component.spec.ts
    ├── login.component.ts
    └── logout
        ├── logout.component.html
        ├── logout.component.scss
        ├── logout.component.spec.ts
        └── logout.component.ts

I have the following AppRoutingModule:

import { NgModule } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
import { AuthGuard } from "security/auth.guard";
import { permissions } from "security/permissions";
import { CampaignComponent } from "./campaign/campaign.component";
import { CampaignListComponent } from "./campaign/campaign-list/campaign-list.component";
import { CampaignFormComponent } from "./campaign/campaign-form/campaign-form.component";
import { CampaignShowComponent } from "./campaign/campaign-show/campaign-show.component";
import { ChannelComponent } from "./channel/channel.component";
import { ChannelFormComponent } from "./channel/channel-form/channel-form.component";
import { ChannelListComponent } from "./channel/channel-list/channel-list.component";
import { ChannelShowComponent } from "./channel/channel-show/channel-show.component";
import { DashboardComponent } from "./dashboard.component";
import { InvoiceComponent } from "./invoice/invoice.component";
import { InvoiceFormComponent } from "./invoice/invoice-form/invoice-form.component";
import { InvoiceListComponent } from "./invoice/invoice-list/invoice-list.component";
import { LeadComponent } from "./lead/lead.component";
import { LeadFormComponent } from "./lead/lead-form/lead-form.component";
import { LeadListComponent } from "./lead/lead-list/lead-list.component";
import { LeadShowComponent } from "./lead/lead-show/lead-show.component";
import { ProfileFormComponent } from "./profile/profile-form/profile-form.component";
import { ProfileListComponent } from "./profile/profile-list/profile-list.component";
import { ProfileShowComponent } from "./profile/profile-show/profile-show.component";
import { ProfileComponent } from "./profile/profile.component";
import { ProductComponent } from "./product/product.component";
import { ProductFormComponent } from "./product/product-form/product-form.component";
import { ProductListComponent } from "./product/product-list/product-list.component";
import { ProductShowComponent } from "./product/product-show/product-show.component";
import { ServiceComponent } from "./service/service.component";
import { ServiceFormComponent } from "./service/service-form/service-form.component";
import { ServiceShowComponent } from "./service/service-show/service-show.component";
import { ServiceListComponent } from "./service/service-list/service-list.component";
import { ContractListComponent } from "./contract/contract-list/contract-list.component";
import { ContractComponent } from "./contract/contract.component";
import { OpportunityFormComponent } from "./opportunity/opportunity-form/opportunity-form.component";
import { OpportunityShowComponent } from "./opportunity/opportunity-show/opportunity-show.component";
import { OpportunityListComponent } from "./opportunity/opportunity-list/opportunity-list.component";
import { OpportunityComponent } from "./opportunity/opportunity.component";
import { MarketerComponent } from "./marketer/marketer.component";
import { MarketerFormComponent } from "./marketer/marketer-form/marketer-form.component";
import { MarketerListComponent } from "./marketer/marketer-list/marketer-list.component";

const routes: Routes = [
  {
    path: "",
    component: DashboardComponent,
    canActivate: [AuthGuard],
    children: [
      { path: "channel", component: ChannelComponent },
      {
        path: "channel/edit/:id",
        component: ChannelFormComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.CHANNEL_EDIT },
      },
      {
        path: "channel/list",
        component: ChannelListComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.CHANNEL_LIST },
      },
      {
        path: "channel/show/:id",
        component: ChannelShowComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.CHANNEL_SHOW },
      },
      { path: "campaign", component: CampaignComponent },
      {
        path: "campaign/edit/:id",
        component: CampaignFormComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.CAMPAIGN_EDIT },
      },
      {
        path: "campaign/list",
        component: CampaignListComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.CAMPAIGN_LIST },
      },
      { path: "profile", component: ProfileComponent },
      {
        path: "campaign/show/:id",
        component: CampaignShowComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.CAMPAIGN_SHOW },
      },
      { path: "invoice", component: InvoiceComponent },
      {
        path: "invoice/edit/:id",
        component: InvoiceFormComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.INVOICE_EDIT },
      },
      {
        path: "invoice/list",
        component: InvoiceListComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.INVOICE_LIST },
      },
      { path: "user", component: ProfileComponent },
      {
        path: "profile/list",
        component: ProfileListComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.USER_LIST },
      },
      {
        path: "profile/edit/:id",
        component: ProfileFormComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.USER_EDIT },
      },
      {
        path: "profile/show/:id",
        component: ProfileShowComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.USER_SHOW },
      },
      { path: "lead", component: LeadComponent },
      {
        path: "lead/edit/:id",
        component: LeadFormComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.LEAD_EDIT },
      },
      {
        path: "lead/list",
        component: LeadListComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.LEAD_LIST },
      },
      {
        path: "lead/show/:id",
        component: LeadShowComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.LEAD_SHOW },
      },
      { path: "product", component: ProductComponent },
      {
        path: "product/edit/:id",
        component: ProductFormComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.PRODUCT_EDIT },
      },
      {
        path: "product/list",
        component: ProductListComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.PRODUCT_LIST },
      },
      {
        path: "product/show/:id",
        component: ProductShowComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.PRODUCT_SHOW },
      },
      { path: "service", component: ServiceComponent },
      {
        path: "service/edit/:id",
        component: ServiceFormComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.SERVICE_EDIT },
      },
      {
        path: "service/list",
        component: ServiceListComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.SERVICE_LIST },
      },
      {
        path: "service/show/:id",
        component: ServiceShowComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.SERVICE_SHOW },
      },
      { path: "contract", component: ContractComponent },
      {
        path: "contract/list",
        component: ContractListComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.CONTRACT_LIST },
      },
      { path: "opportunity", component: OpportunityComponent },
      {
        path: "opportunity/list",
        component: OpportunityListComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.OPPORTUNITY_LIST },
      },
      {
        path: "opportunity/edit/:id",
        component: OpportunityFormComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.OPPORTUNITY_EDIT },
      },
      {
        path: "opportunity/show/:id",
        component: OpportunityShowComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.OPPORTUNITY_SHOW },
      },
      { path: "marketer", component: MarketerComponent },
      {
        path: "marketer/list",
        component: MarketerListComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.MARKETER_LIST },
      },
      {
        path: "marketer/edit/:id",
        component: MarketerFormComponent,
        canActivate: [AuthGuard],
        data: { permission: permissions.MARKETER_EDIT },
      },
    ],
  },
];

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

I am trying to restrict access to some URLs of the app based on the currently logged in user role. This can be achieved using route guards, in my case other teammates created the AuthGuard component:

import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot } from '@angular/router';
import { ProfileRole } from '../models/profile-role.enum';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private router: Router) {}

  canActivate(routeSnapshot: ActivatedRouteSnapshot): boolean {
    let res = false;
    const route = routeSnapshot.firstChild; // <------ .data returns {}
    const permission: Array<ProfileRole> = route.data['permission']; // <----- will throw an error

    if (localStorage.getItem('key')) {
      if (!permission) {
        res = true;
      } else if (permission.includes(localStorage.getItem('role') as ProfileRole)) {
        res = true;
      }
    } else {
      this.router.navigateByUrl('/login');
    }

    return res;
  }
}

I've modified this code a bit but I am still unable to get data from the child routes. However if I add data to the parent route this will appear as a "filled" object.

In my research of the issue I've tried different solutions or just tried to see if data was not empty when accessing it from other components (AppComponent, DashboardComponent, CampaignListComponent) but as of today it's been imposible to find a fix.

Here I leave you the posts that where more relevant on the topic whose solutions I tried implementing:

I guess the problem has to do with lazy loading the DashboardRoutes but I'm not entirely sure because data from the parent route is indeed loaded. Anyway, I hope someone can shed some light in the matter. Thanks in advance. Ask for any more code if you see it needed.

Upvotes: 0

Views: 256

Answers (0)

Related Questions