2 компонента для одного пути

Мой проект Angular имеет следующую структуру папок:

.
├── private
│   ├── components
│   └── private-routing.module.ts
├── public
│   ├── components
│   ├── public-routing.module.ts
├── shared
│   ├── components
│   ├── shared-routing.module.ts

Частный каталог зависит от пользователей, вошедших в систему, общий каталог — для пользователей, которые не вошли в систему, а общий каталог содержит компоненты, которые могут использоваться обоими типами пользователей.

Моя цель — иметь два разных компонента, но оба должны указывать на путь ''. Итак, у меня есть HomeComponent в личном каталоге, но также есть HomeComponent в общедоступном каталоге. Т.е. если пользователь вошел в систему, необходимо активировать HomeComponent из частного каталога, в противном случае HomeComponent из общедоступного каталога.

Моя проблема в том, что у меня есть 2 маршрута с путем ''.

частный-routing.module.ts:

const routes: Routes = [
  { path: '', component: HomeComponent , canActivate: [LoginGuard], data: { isPrivate: true }, title: "Home"}
]

общественный-routing.module.ts:

const routes: Routes = [
  {path: '', component: HomeComponent, data: {isPrivate: false}, title: "Home"}
]

Это мой охранник:

@Injectable()
export class PermissionService {
  constructor(private _routerService: RouterService, private loginService: LoginService, private router: Router) {}

  canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
    return this.loginService.isUserLoggedIn().pipe(
      map((isLoggedIn: boolean): boolean => {
        if (next.routeConfig?.path === '') {
          if (isLoggedIn) {
            console.info('User is logged in');
          }
          else {
            console.info('Unknown user');
          }
        }

        if (next.routeConfig?.path === 'login' || next.routeConfig?.path === 'register') {
          if (isLoggedIn) {
            // If the user is already logged in and trying to access /login or /register, redirect to /
            this.router.navigate(['/']).then(() => window.scrollTo(0, 0));
            return false; 
          }
          // Allow access to /login and /register for unauthenticated users
          return true;
        } else if (!isLoggedIn) {
          // User is not logged in, navigate to /login if trying to access protected routes
          const publicPages: string[] = ['/register', '/forgot-password'];
          if (!publicPages.includes(this.router.url) && this._routerService.isPrivate()) {
            this.router.navigate(['/login']).then(() => window.scrollTo(0, 0));
          }
          return false; 
        } else {
          return true;
        }
      })
    );
  }
}
export const LoginGuard: CanActivateFn = (next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> => {
  return inject(PermissionService).canActivate(next, state);
}

Если пользователь вошел в систему, я получаю журнал. Пользователь вошел в систему, и можно отобразить HomeComponent из частного каталога. Однако, если пользователь не вошел в систему, я получаю журнал «Неизвестный пользователь», но HomeComponent из общедоступного каталога не будет отображаться.

то, что вы ищете, скорее всего, может соответствовать «охраннику». Если canMatch возвращает false — алгоритм сопоставления маршрута просто перейдет к следующему маршруту и ​​попытается сопоставить его.

Andrei 31.05.2024 10:21
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
1
1
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как упоминалось в комментариях, вот как вы можете это реализовать: мы можем создать функцию, которая возвращает true или false, в зависимости от разрешений.

export const canMatchPrivateFn = () => {
  const auth = inject(AuthService);
  return auth.isLoggedIn;
};

export const canMatchFn = () => {
  const auth = inject(AuthService);
  return auth.isLoggedIn.pipe(map((x: boolean) => !x));
};

Эти две функции настраиваются для соответствующих частей маршрутизации с помощью canMatch

export const routes: Routes = [
  {
    // here users route component will get lazy loaded, by using a callback with import statement!
    path: '',
    canMatch: [canMatchPrivateFn],
    loadChildren: () =>
      import('./app/private/private.module').then((mod) => mod.PrivateModule),
  },
  {
    // here users route component will get lazy loaded, by using a callback with import statement!
    path: '',
    canMatch: [canMatchFn],
    loadChildren: () =>
      import('./app/public/public.module').then((mod) => mod.PublicModule),
  },
];

После этого, когда мы переключаем флаг на сервисе, мы видим, как маршруты изменяются на основе асинхронного вызова (имитирует API).

import { Injectable } from '@angular/core';
import { delay } from 'rxjs/operators';
import { of } from 'rxjs';
@Injectable({
  providedIn: 'root',
})
export class AuthService {
  isLoggedIn = of(true).pipe(delay(1000));
  constructor() {}
}

Полный код:

import { Component, inject } from '@angular/core';
import { provideRouter, Routes, RouterModule } from '@angular/router';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import { AuthService } from './auth.service';
import { map } from 'rxjs';

export const canMatchPrivateFn = () => {
  const auth = inject(AuthService);
  return auth.isLoggedIn;
};

export const canMatchFn = () => {
  const auth = inject(AuthService);
  return auth.isLoggedIn.pipe(map((x: boolean) => !x));
};

export const routes: Routes = [
  {
    // here users route component will get lazy loaded, by using a callback with import statement!
    path: '',
    canMatch: [canMatchPrivateFn],
    loadChildren: () =>
      import('./app/private/private.module').then((mod) => mod.PrivateModule),
  },
  {
    // here users route component will get lazy loaded, by using a callback with import statement!
    path: '',
    canMatch: [canMatchFn],
    loadChildren: () =>
      import('./app/public/public.module').then((mod) => mod.PublicModule),
  },
];
@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterModule],
  template: `
    <router-outlet/>
  `,
})
export class App {
  name = 'Angular';
}

bootstrapApplication(App, {
  providers: [provideRouter(routes)],
});

Демо-версия Stackblitz

Другие вопросы по теме