Данные дочерних маршрутов Angular (ленивая загрузка в AppRoutingModule) всегда являются пустым объектом ({}). Попытка получить к нему доступ из охранника маршрута

Я боролся с этой проблемой около недели, но все, что я нашел в Интернете (и пробовал), не помогает.

У меня есть проект AngularJS (Angular v11) со следующей структурой:

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

У меня есть следующий модуль 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 {}

Я пытаюсь ограничить доступ к некоторым URL-адресам приложения на основе текущей роли пользователя, вошедшего в систему. Этого можно достичь с помощью защитников маршрута, в моем случае другие товарищи по команде создали компонент AuthGuard:

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;
  }
}

Я немного изменил этот код, но я все еще не могу получить данные из дочерних маршрутов. Однако, если я добавлю данные к родительскому маршруту, он появится как заполненный объект.

В своем исследовании проблемы я пробовал разные решения или просто пытался проверить, не были ли данные пустыми при доступе к ним из других компонентов (AppComponent, DashboardComponent, CampaignListComponent), но на сегодняшний день найти исправление невозможно.

Здесь я оставляю вам сообщения, которые более актуальны по теме, решения которой я пытался реализовать:

Я предполагаю, что проблема связана с ленивой загрузкой DashboardRoutes, но я не совсем уверен, потому что данные из родительского маршрута действительно загружены. В любом случае, я надеюсь, что кто-нибудь сможет пролить свет на этот вопрос. Заранее спасибо. Спросите еще код, если считаете, что он нужен.


person Angel Bonilla    schedule 24.03.2021    source источник