Angular. Роутинг для продвинутых — мешаем каталог с сайтом
Запись от 12.09.2017
Задача такая — преобразовать навигацию по сайту:
То есть, исключить разводящую страницу «/catalog» и переместить все разделы уровнем ниже, при этом не смешав с 404-ой ошибкой.
Для этой задачи понадобится создать сервис, который позволит переключать правила навигации с дефолтной навигации:
Плюс, надо будет отслеживать текущий роут «activatedRoute» в компоненте, который привяжем к правилу «**» дефолтной навигации.
Так что для начала из основного роутинга приложения (app-routing.module.ts) убираем правила роутинга для каталога и назначаем в конце маршрутов:
В модуле приложения нужно добавить ключ «entryComponents» с указанием компонентов страниц каталога, т.к. они будут использоваться во втором динамическом роутинге для каталога.
Код компонента «CatalogRoutingComponent»:
Здесь компонент подписывается на изменения адреса страницы и в зависимости от него через сервис назначает дефолтный роутинг или роутинг каталога. А переменная «showCommonPage» используется для передачи управления следующему компоненту в правиле «**», что видно по используемому шаблону.
Остается дело за сервисом (провайдится в app):
Переменные:
isCatalogRoutes — true, если активен роутинг каталога;
catalogRoutes — правила роутинга для каталога и его подразделов;
defaultRoutes — здесь будет храниться дефолтный конфиг роутинга;
routeSubscription — подписка на изменения роутинга, что бы не утекала память на множестве подписок.
По методам добавить нечего, названия достаточно ёмкие. Только в checkUrlSegments() должна быть написана действительная проверка, является ли url частью каталога. Тут может быть что угодно: например, проверка по заранее готовому массиву, или обращение к бекенду за актуальными кодами разделов или что-то ещё.
/ /news /contacts /catalog /catalog/:sectionCode /catalog/:sectionCode/news /catalog/:sectionCode/shares ** (404 error) |
-> |
/ /news /contacts /:sectionCode /:sectionCode/news /:sectionCode/shares ** (404 error) |
То есть, исключить разводящую страницу «/catalog» и переместить все разделы уровнем ниже, при этом не смешав с 404-ой ошибкой.
Для этой задачи понадобится создать сервис, который позволит переключать правила навигации с дефолтной навигации:
/
/news
/contacts
**
на навигацию по каталогу:/:sectionCode
/:sectionCode/news
/:sectionCode/shares
**
Плюс, надо будет отслеживать текущий роут «activatedRoute» в компоненте, который привяжем к правилу «**» дефолтной навигации.
Так что для начала из основного роутинга приложения (app-routing.module.ts) убираем правила роутинга для каталога и назначаем в конце маршрутов:
{
path: '**',
component: CatalogRoutingComponent,
}
В модуле приложения нужно добавить ключ «entryComponents» с указанием компонентов страниц каталога, т.к. они будут использоваться во втором динамическом роутинге для каталога.
Код компонента «CatalogRoutingComponent»:
@Component({
selector: 'app-catalog-routing',
template: '<app-common-page *ngIf="showCommonPage"></app-common-page>',
})
export class CatalogRoutingComponent implements OnInit {
public showCommonPage: boolean = false;
constructor(
private activatedRoute: ActivatedRoute,
private catalogRoutingService: CatalogRoutingService,
private router: Router,
) {}
public ngOnInit(): void {
this.activatedRoute.url.subscribe(params => {
if (this.catalogRoutingService.checkUrlSegments(params)) {
this.catalogRoutingService.setCatalogRoutes();
}
this.updateShowCommonPage();
});
const routeSubscription = this.router.events.subscribe(event => {
if (event instanceof NavigationStart) {
const urlTree = this.router.parseUrl(event['url']);
if (urlTree) {
const urlSegments = (urlTree.root.children['primary'])
? urlTree.root.children['primary'].segments : [];
if (!this.catalogRoutingService.checkUrlSegments(urlSegments)) {
this.catalogRoutingService.setDefaultRoutes();
this.updateShowCommonPage();
}
}
}
});
this.catalogRoutingService.setRouteSubscription(routeSubscription);
}
private updateShowCommonPage(): void {
this.showCommonPage = !this.catalogRoutingService.getIsCatalogRoutes();
}
}
Здесь компонент подписывается на изменения адреса страницы и в зависимости от него через сервис назначает дефолтный роутинг или роутинг каталога. А переменная «showCommonPage» используется для передачи управления следующему компоненту в правиле «**», что видно по используемому шаблону.
Остается дело за сервисом (провайдится в app):
@Injectable()
export class CatalogRoutingService {
private isCatalogRoutes: boolean = false;
private catalogRoutes: Routes = [{
path: ':sectionCode',
component: PageCatalogSectionComponent,
}, {
path: ':sectionCode/news',
component: PageCatalogNewsComponent,
}, {
path: ':sectionCode/shares',
component: PageCatalogSharesComponent,
}];
private defaultRoutes: Routes;
private routeSubscription: Subscription;
constructor(
private router: Router,
) {
this.defaultRoutes = this.router.config;
}
public getIsCatalogRoutes(): boolean {
return this.isCatalogRoutes;
}
public setCatalogRoutes(): void {
this.isCatalogRoutes = true;
this.router.resetConfig(this.catalogRoutes);
this.router.navigateByUrl(this.router.url);
}
public setDefaultRoutes(): void {
this.router.resetConfig(this.defaultRoutes);
this.isCatalogRoutes = false;
}
public setRouteSubscription(subscription: Subscription): void {
if (this.routeSubscription) {
this.routeSubscription.unsubscribe();
}
this.routeSubscription = subscription;
}
public checkUrlSegments(url: UrlSegment[]): boolean {
return true; // Некоторое условие для проверки `url`
}
}
Переменные:
isCatalogRoutes — true, если активен роутинг каталога;
catalogRoutes — правила роутинга для каталога и его подразделов;
defaultRoutes — здесь будет храниться дефолтный конфиг роутинга;
routeSubscription — подписка на изменения роутинга, что бы не утекала память на множестве подписок.
По методам добавить нечего, названия достаточно ёмкие. Только в checkUrlSegments() должна быть написана действительная проверка, является ли url частью каталога. Тут может быть что угодно: например, проверка по заранее готовому массиву, или обращение к бекенду за актуальными кодами разделов или что-то ещё.