Мой проект 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 из общедоступного каталога не будет отображаться.





Как упоминалось в комментариях, вот как вы можете это реализовать: мы можем создать функцию, которая возвращает 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)],
});
то, что вы ищете, скорее всего, может соответствовать «охраннику». Если canMatch возвращает
false— алгоритм сопоставления маршрута просто перейдет к следующему маршруту и попытается сопоставить его.