Вложенная маршрутизация в Angular - PullRequest
1 голос
/ 11 июля 2020

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

На верхнем уровне приложение angular, которое я разрабатываю, предоставляет путь входа и пути к 4 отдельным панелям мониторинга в зависимости от того, кто входит в систему. Эта часть работает должным образом.

Для каждой панели инструментов у меня есть боковая навигация, которая более или менее одинакова (некоторые параметры отображаются только для определенных типов пользователей). В дашборде у меня вложенная розетка роутера. Каждый раз, когда я пытаюсь загрузить модуль во вложенную розетку, Angular не может сопоставить путь. Вот что у меня есть:

app-routing.module.ts

const routes: Routes = [
  { path: '', pathMatch: 'full', redirectTo: 'login' },
  { path: 'login', loadChildren: () => import('./modules/auth/auth.module').then(m => m.AuthModule) },
  //{ path: 'dashboard', loadChildren: () => import('./modules/dashboard/dashboard.module').then(m => m.DashboardModule) }
  { path: 'admin', loadChildren: () => import('./modules/admin/admin.module').then(m => m.AdminModule) },
];

admin-routing.module.ts


const routes: Routes = [
  { path: '', pathMatch: 'full', component: AdminComponent, children: [
    { path: 'employee', loadChildren: () => import('./../employee/employee.module').then(m => m.EmployeeModule) },
    { path: 'attendance', loadChildren: () => import('./../attendance/attendance.module').then(m => m.AttendanceModule) },
    { path: 'customer', loadChildren: () => import('./../customer/customer.module').then(m => m.CustomerModule) },
    { path: 'order', loadChildren: () => import('./../order/order.module').then(m => m.OrderModule) },
    { path: 'expense', loadChildren: () => import('./../expense/expense.module').then(m => m.ExpenseModule) },
  ]},
];

app.component. html

<router-outlet></router-outlet>

admin.component. html

<mat-drawer-container mode="side" id="dashboard-drawer-container" hasBackdrop="false">
  <mat-drawer #drawer id="sidenav-container">
    <app-sidenav></app-sidenav>
  </mat-drawer>
  <div id="dashboard-container">
    <router-outlet></router-outlet>
  </div>
</mat-drawer-container>

Теперь ожидаемое поведение выглядит следующим образом:

  1. При переходе к / admin компонент AdminComponent будет отображен, и будет видна боковая навигация
  2. При нажатии ссылки на боковой панели контент должен отображаться во вложенном маршрутизаторе в компоненте администратора (например, admin / employee)
  3. Когда доступ к другим маршрутам осуществляется внутри модуля, загруженного в (2), он должен отображаться внутри выхода в этом модуле (например, admin / employee /: id) для страницы сведений о сотруднике, где модуль сотрудника имеет вложенный маршрутизатор

Я пробовал использовать именованные розетки, но продолжал выдавать ошибку. Если я уберу детей из административных маршрутов и сделаю их независимыми маршрутами, это вроде как работает, но контент будет отображаться на самом внешнем (приложении) выходе маршрутизатора, а боковая навигация не отображается.

Любая помощь или предложение будем очень признательны.

Ответы [ 2 ]

2 голосов
/ 11 июля 2020

Давайте разберем проблему на небольшую:

app.module.ts

const routes: Routes = [
  {
    path: '',
    // pathMatch: 'full',
    children: [
      {
        path: 'foo',
        component: FooComponent
      },
    ],
  },
  {
    path: '**',
    component: NotFoundComponent,
  }
];

app.component. html

<router-outlet></router-outlet>

<button routerLink="/foo">go to foo</button>

демо ng-run .

Если мы щелкнем по кнопке, маршрутизатор Angular запланирует переход маршрута . Это включает в себя довольно интересный процесс, который состоит из нескольких фаз , .

Одна из этих фаз называется Применить перенаправления , и именно здесь перенаправления разрешаются и где NoMatch ошибки происходят из. Здесь также можно найти больше информации о pathMatch: 'full'. На этом этапе он будет go через каждый объект конфигурации и попытается найти первый из них, который соответствует выданному URL-адресу (например, /foo).

Сначала он столкнется с этим one (это происходит в matchSegmentAgainstRoute):

{
  path: '',
  // pathMatch: 'full',
  children: [
    {
      path: 'foo',
      component: FooComponent
    },
  ],
},

тогда будет вызвана функция match:

const {matched, consumedSegments, lastChild} = match(rawSegmentGroup, route, segments);

здесь мы останавливаемся на route.path === '':

if (route.path === '') {
  if ((route.pathMatch === 'full') && (segmentGroup.hasChildren() || segments.length > 0)) {
    return {matched: false, consumedSegments: [], lastChild: 0, positionalParamSegments: {}};
  }

  return {matched: true, consumedSegments: [], lastChild: 0, positionalParamSegments: {}};
}

Итак, вот один случай, когда опция pathMatch имеет значение. При текущей конфигурации (pathMatch не задано) будет достигнуто

return {matched: true, consumedSegments: [], lastChild: 0, positionalParamSegments: {}};

, а затем он перейдет к go через массив children. Итак, в этом случае FooComponent будет успешно отображаться.

Но если у нас есть pathMatch: 'full', тогда выражение

if ((route.pathMatch === 'full') && (segmentGroup.hasChildren() || segments.length > 0)) { }

будет true, потому что segments.length > 0, в данном случае сегменты - ['foo']. Итак, мы получим matched: false, что означает, что FooComponent не появится в представлении.

0 голосов
/ 11 июля 2020

, если вам нужно использовать другой пользовательский интерфейс для разных модулей, вы можете добиться этого, указав родительский компонент в app-routing.module.ts.

app-routing.module.ts.

    const routes: Routes = [
      {
        path: '',
        component: AdminComponent, //you can set different UI like navigation/header 
        children: [
         { path: '',redirectTo: 'dashboard',pathMatch: 'full'}, //set default redirect
         { path: 'dashboard', loadChildren: () =>import('./../dashboard/dashboard.module').then(m => m.DashboardModule) },
         { path: 'employee', loadChildren: () => import('./../employee/employee.module').then(m => m.EmployeeModule) },
         { path: 'attendance', loadChildren: () => import('./../attendance/attendance.module').then(m => m.AttendanceModule) },
         { path: 'customer', loadChildren: () => import('./../customer/customer.module').then(m => m.CustomerModule) },
         { path: 'order', loadChildren: () => import('./../order/order.module').then(m => m.OrderModule) },
         { path: 'expense', loadChildren: () => import('./../expense/expense.module').then(m => m.ExpenseModule) },
        ]
      },
      {
        path: '',
        component: AuthComponent, //different UI for child components, without navigation
        children: [
         { path: 'maintenance',loadChildren: () => import('./../maintenance/maintenance.module').then(m => m.MaintenanceModule) },
         { path: 'login',loadChildren () => import('./../authentication/authentication.module').then(m => m.AuthenticationModule) },
         { path: 'landing',loadChildren: () => import('./../landing/landing.module').then(m => m.LandingModule) }
        ]
      }

Ваши подмодули, например: admin / employee /: id, будут отображать пользовательский интерфейс родителя (например: AdminComponent),

...