From fd15d7ee53ddc6f994dccbad7b69b378bf4758c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20B=C3=BChler?= Date: Mon, 5 Aug 2024 11:06:10 +0200 Subject: [PATCH] Fix angular not reusing tab component over multiple routes Use a custom route matcher to only use one single route for all routes using the PluginTabComponent --- src/app/app-routing.module.ts | 103 +++++++++++++++++++++++++++++++--- 1 file changed, 94 insertions(+), 9 deletions(-) diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 54f8e53..ed98425 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -15,7 +15,7 @@ */ import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; +import { RouterModule, Routes, UrlMatcher, UrlMatchResult, UrlSegment } from '@angular/router'; import { DataDetailComponent } from './components/data-detail/data-detail.component'; import { ExperimentDataComponent } from './components/experiment-data/experiment-data.component'; import { ExperimentTimelineComponent } from './components/experiment-timeline/experiment-timeline.component'; @@ -26,13 +26,98 @@ import { PluginTabComponent } from './components/plugin-tab/plugin-tab.component import { SettingsPageComponent } from './components/settings-page/settings-page.component'; import { TimelineStepComponent } from './components/timeline-step/timeline-step.component'; +const NUMBER_REGEX = /^[0-9]+$/; + +const extraTabsMatcher: UrlMatcher = (segments: UrlSegment[], group, route): UrlMatchResult | null => { + const consumed: UrlSegment[] = []; + const params: { [props: string]: UrlSegment } = {}; + + let tabId: UrlSegment | null = null; + let pluginId: UrlSegment | null = null; + + // match: /experiments/:experimentId + let index = 0; + if (segments[index]?.path === "experiments") { + consumed.push(segments[index]); + index += 1; + if ((segments[index]?.path ?? "").match(NUMBER_REGEX)) { + params.experimentId = segments[index]; + consumed.push(segments[index]); + index += 1; + } else { + return null; + } + } + + console.log(consumed, params) + + // match: ./extra[/:path]/:templateTabId + if (segments[index]?.path !== "extra") { + return null; + } + consumed.push(segments[index]); + index += 1; + if (segments[index + 1]?.path.match(NUMBER_REGEX)) { + // push [/:path] + params.path = segments[index]; + consumed.push(segments[index]); + index += 1; + // push /:templateTabId + tabId = segments[index]; + consumed.push(segments[index]); + index += 1; + } else if (segments[index]?.path.match(NUMBER_REGEX)) { + // push /:templateTabId + tabId = segments[index]; + consumed.push(segments[index]); + index += 1; + } + + if (tabId == null) { + // sanity check + return null; + } + params.templateTabId = tabId; + + console.log(consumed, params) + + // found full match? + if (index === segments.length) { + return { + consumed: consumed, + posParams: params, + } + } + + // match: ./plugin/:pluginId + if (segments[index]?.path !== "plugins") { + return null; + } + consumed.push(segments[index]); + index += 1; + if (segments[index]?.path.match(NUMBER_REGEX)) { + pluginId = segments[index]; + consumed.push(segments[index]); + index += 1; + } + + console.log(consumed, params) + + // found full match? + if (index === segments.length && pluginId != null) { + params.pluginId = pluginId; + return { + consumed: consumed, + posParams: params, + } + } + + return null; +} + const routes: Routes = [ { path: '', component: ExperimentsPageComponent }, { path: 'settings', component: SettingsPageComponent }, - { path: 'extra/:templateTabId', component: PluginTabComponent }, - { path: 'extra/:templateTabId/plugin/:pluginId', component: PluginTabComponent }, - { path: 'extra/:path/:templateTabId', component: PluginTabComponent }, - { path: 'extra/:path/:templateTabId/plugin/:pluginId', component: PluginTabComponent }, { path: 'experiments', component: ExperimentsPageComponent }, { path: 'experiments/:experimentId', redirectTo: "info" }, { path: 'experiments/:experimentId/info', component: ExperimentComponent }, @@ -43,10 +128,10 @@ const routes: Routes = [ { path: 'experiments/:experimentId/timeline', component: ExperimentTimelineComponent }, { path: 'experiments/:experimentId/timeline/:step', component: TimelineStepComponent }, { path: 'experiments/:experimentId/timeline/:step/:stepTabId', component: TimelineStepComponent }, - { path: 'experiments/:experimentId/extra/:templateTabId', component: PluginTabComponent }, - { path: 'experiments/:experimentId/extra/:templateTabId/plugin/:pluginId', component: PluginTabComponent }, - { path: 'experiments/:experimentId/extra/:path/:templateTabId', component: PluginTabComponent }, - { path: 'experiments/:experimentId/extra/:path/:templateTabId/plugin/:pluginId', component: PluginTabComponent }, + {/* path: '[experiments/:experimentId/]extra/[:path/]:templateTabId/[plugins/:pluginId]' */ + matcher: extraTabsMatcher, + component: PluginTabComponent, + }, ]; @NgModule({