BACKGROUND:
I am trying my hand at an angular application and I'm having a huge issue with wrapping my head around routing.
I have 2 questions that I need to figure out that I have been struggling with for a few days now and at this point, I am just wasting time going in circles.
DETAILS:
I have a routes tree defined in my root app module like this:
export const ROUTES: Routes = [
{
path: "callback",
component: CallbackComponent
},
{
path: "secure",
loadChildren: "./secure/secure.module#SecureModule",
canActivate: [AuthGuard]
},
{
path: "public",
loadChildren: "./public/public.module#PublicModule"
},
{
path: "",
redirectTo: "public",
pathMatch: "full"
},
{ path: "**", component: PageNotFoundComponent }
];
@NgModule({
declarations: [AppComponent, PageNotFoundComponent],
imports: [
AuthModule,
BrowserModule,
BrowserAnimationsModule,
HttpClientModule,
RouterModule.forRoot(ROUTES, {enableTracing: (environment.production === false)}),
StoreModule.forRoot(reducers, { metaReducers }), //sets the entire app up to use ngrx store and applies the metaReducers class as a parent to all reducers used throughout the system. this helps with the debug tools
EffectsModule.forRoot(effects),
StoreRouterConnectingModule,
environment.production === false ? StoreDevtoolsModule.instrument() : [],
],
providers: [
{ provide: ErrorHandler, useClass: AppServices.RollbarErrorHandler },
{
provide: AppServices.RollbarService,
useFactory: AppServices.rollbarFactory
}
],
exports: [AppComponent, PageNotFoundComponent]
})
When I first load my app with the URL localhost:4200, the public path gets loaded. That makes sense to me because the URL pattern matches the "" path so it gets redirected to the "public" path and loads that. This works fine as my public path gets loaded correctly.
The issue I am having comes up when I am authenticating against Auth0 which calls a callback URL defined as localhost:4200/callback after the user has been authenticated. I would think that this URL matches the "callback" route and should load the CallbackComponent. Unfortunately, it doesn't and it loads the public path again.
My CallbackComponent is defined in my AuthModule (where it also exported) which is obviously a separate module. In my experimenting, there is no issue with loading the component in the AppModule pages so I don't think this component being in another module is an issue but figured I'd mention it in case it is.
QUESTIONS
1) Why the heck is the "callback" path not loading when the URL is localhost:4200/callback?
2) Auth0 will pass token information and any errors back to that same URL in the querystring after a hash (eg localhost:4200/callback#error=... or, on success, localhost:4200/callback#access_token=...). Will that have an effect on the path matching? If so, what do I update my path to in order to handle that? If not, I believe that part of the URL will be considered a fragment, so I just get that information off the activatedRoute or is there some other way I am missing to handle fragments in routes?
Thanks in advance for any help.
UPDATE
I'm attaching the Router tracing blocks to show what exactly I'm seeing:
First is the navigation events when I navigate to the root URL
Navigated to http://localhost:4200/
platform-browser.js:380 Router Event: NavigationStart
platform-browser.js:367 NavigationStart(id: 1, url: '/')
platform-browser.js:367 NavigationStart {id: 1, url: "/"}
platform-browser.js:380 Router Event: RouteConfigLoadStart
platform-browser.js:367 RouteConfigLoadStart(path: public)
platform-browser.js:367 RouteConfigLoadStart {route: {…}}
core.js:3675 Angular is running in the development mode. Call enableProdMode() to enable the production mode.
platform-browser.js:380 Router Event: RouteConfigLoadEnd
platform-browser.js:367 RouteConfigLoadEnd(path: public)
platform-browser.js:367 RouteConfigLoadEnd {route: {…}}
platform-browser.js:380 Router Event: RoutesRecognized
platform-browser.js:367 RoutesRecognized(id: 1, url: '/', urlAfterRedirects: '/public', state: Route(url:'', path:'') { Route(url:'public', path:'public') { Route(url:'', path:'') { Route(url:'', path:'') } } } )
platform-browser.js:367 RoutesRecognized {id: 1, url: "/", urlAfterRedirects: "/public", state: RouterStateSnapshot}
platform-browser.js:380 Router Event: NavigationCancel
platform-browser.js:367 NavigationCancel(id: 1, url: '/')
platform-browser.js:367 NavigationCancel {id: 1, url: "/", reason: ""}
platform-browser.js:380 Router Event: NavigationStart
platform-browser.js:367 NavigationStart(id: 2, url: '/')
platform-browser.js:367 NavigationStart {id: 2, url: "/"}
platform-browser.js:380 Router Event: RoutesRecognized
platform-browser.js:367 RoutesRecognized(id: 2, url: '/', urlAfterRedirects: '/public', state: Route(url:'', path:'') { Route(url:'public', path:'public') { Route(url:'', path:'') { Route(url:'', path:'') } } } )
platform-browser.js:367 RoutesRecognized {id: 2, url: "/", urlAfterRedirects: "/public", state: RouterStateSnapshot}
platform-browser.js:380 Router Event: GuardsCheckStart
platform-browser.js:367 GuardsCheckStart(id: 2, url: '/', urlAfterRedirects: '/public', state: Route(url:'', path:'') { Route(url:'public', path:'public') { Route(url:'', path:'') { Route(url:'', path:'') } } } )
platform-browser.js:367 GuardsCheckStart {id: 2, url: "/", urlAfterRedirects: UrlTree, state: RouterStateSnapshot}
platform-browser.js:380 Router Event: ChildActivationStart
platform-browser.js:367 ChildActivationStart(path: '')
platform-browser.js:367 ChildActivationStart {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ActivationStart
platform-browser.js:367 ActivationStart(path: 'public')
platform-browser.js:367 ActivationStart {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ChildActivationStart
platform-browser.js:367 ChildActivationStart(path: 'public')
platform-browser.js:367 ChildActivationStart {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ActivationStart
platform-browser.js:367 ActivationStart(path: '')
platform-browser.js:367 ActivationStart {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ChildActivationStart
platform-browser.js:367 ChildActivationStart(path: '')
platform-browser.js:367 ChildActivationStart {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ActivationStart
platform-browser.js:367 ActivationStart(path: '')
platform-browser.js:367 ActivationStart {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: GuardsCheckEnd
platform-browser.js:367 GuardsCheckEnd(id: 2, url: '/', urlAfterRedirects: '/public', state: Route(url:'', path:'') { Route(url:'public', path:'public') { Route(url:'', path:'') { Route(url:'', path:'') } } } , shouldActivate: true)
platform-browser.js:367 GuardsCheckEnd {id: 2, url: "/", urlAfterRedirects: UrlTree, state: RouterStateSnapshot, shouldActivate: true}
platform-browser.js:380 Router Event: ResolveStart
platform-browser.js:367 ResolveStart(id: 2, url: '/', urlAfterRedirects: '/public', state: Route(url:'', path:'') { Route(url:'public', path:'public') { Route(url:'', path:'') { Route(url:'', path:'') } } } )
platform-browser.js:367 ResolveStart {id: 2, url: "/", urlAfterRedirects: UrlTree, state: RouterStateSnapshot}
platform-browser.js:380 Router Event: ResolveEnd
platform-browser.js:367 ResolveEnd(id: 2, url: '/', urlAfterRedirects: '/public', state: Route(url:'', path:'') { Route(url:'public', path:'public') { Route(url:'', path:'') { Route(url:'', path:'') } } } )
platform-browser.js:367 ResolveEnd {id: 2, url: "/", urlAfterRedirects: UrlTree, state: RouterStateSnapshot}
platform-browser.js:380 Router Event: ActivationEnd
platform-browser.js:367 ActivationEnd(path: '')
platform-browser.js:367 ActivationEnd {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ChildActivationEnd
platform-browser.js:367 ChildActivationEnd(path: '')
platform-browser.js:367 ChildActivationEnd {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ActivationEnd
platform-browser.js:367 ActivationEnd(path: '')
platform-browser.js:367 ActivationEnd {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ChildActivationEnd
platform-browser.js:367 ChildActivationEnd(path: 'public')
platform-browser.js:367 ChildActivationEnd {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ActivationEnd
platform-browser.js:367 ActivationEnd(path: 'public')
platform-browser.js:367 ActivationEnd {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ChildActivationEnd
platform-browser.js:367 ChildActivationEnd(path: '')
platform-browser.js:367 ChildActivationEnd {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: NavigationEnd
platform-browser.js:367 NavigationEnd(id: 2, url: '/', urlAfterRedirects: '/public')
platform-browser.js:367 NavigationEnd {id: 2, url: "/", urlAfterRedirects: "/public"}
This is the router tracing when I go straight to the callback url:
Navigated to http://localhost:4200/callback
platform-browser.js:380 Router Event: NavigationStart
platform-browser.js:367 NavigationStart(id: 1, url: '/')
platform-browser.js:367 NavigationStart {id: 1, url: "/"}
platform-browser.js:380 Router Event: RouteConfigLoadStart
platform-browser.js:367 RouteConfigLoadStart(path: public)
platform-browser.js:367 RouteConfigLoadStart {route: {…}}
core.js:3675 Angular is running in the development mode. Call enableProdMode() to enable the production mode.
platform-browser.js:380 Router Event: RouteConfigLoadEnd
platform-browser.js:367 RouteConfigLoadEnd(path: public)
platform-browser.js:367 RouteConfigLoadEnd {route: {…}}
platform-browser.js:380 Router Event: RoutesRecognized
platform-browser.js:367 RoutesRecognized(id: 1, url: '/', urlAfterRedirects: '/public', state: Route(url:'', path:'') { Route(url:'public', path:'public') { Route(url:'', path:'') { Route(url:'', path:'') } } } )
platform-browser.js:367 RoutesRecognized {id: 1, url: "/", urlAfterRedirects: "/public", state: RouterStateSnapshot}
platform-browser.js:380 Router Event: NavigationCancel
platform-browser.js:367 NavigationCancel(id: 1, url: '/')
platform-browser.js:367 NavigationCancel {id: 1, url: "/", reason: ""}
platform-browser.js:380 Router Event: NavigationStart
platform-browser.js:367 NavigationStart(id: 2, url: '/')
platform-browser.js:367 NavigationStart {id: 2, url: "/"}
platform-browser.js:380 Router Event: RoutesRecognized
platform-browser.js:367 RoutesRecognized(id: 2, url: '/', urlAfterRedirects: '/public', state: Route(url:'', path:'') { Route(url:'public', path:'public') { Route(url:'', path:'') { Route(url:'', path:'') } } } )
platform-browser.js:367 RoutesRecognized {id: 2, url: "/", urlAfterRedirects: "/public", state: RouterStateSnapshot}
platform-browser.js:380 Router Event: GuardsCheckStart
platform-browser.js:367 GuardsCheckStart(id: 2, url: '/', urlAfterRedirects: '/public', state: Route(url:'', path:'') { Route(url:'public', path:'public') { Route(url:'', path:'') { Route(url:'', path:'') } } } )
platform-browser.js:367 GuardsCheckStart {id: 2, url: "/", urlAfterRedirects: UrlTree, state: RouterStateSnapshot}
platform-browser.js:380 Router Event: ChildActivationStart
platform-browser.js:367 ChildActivationStart(path: '')
platform-browser.js:367 ChildActivationStart {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ActivationStart
platform-browser.js:367 ActivationStart(path: 'public')
platform-browser.js:367 ActivationStart {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ChildActivationStart
platform-browser.js:367 ChildActivationStart(path: 'public')
platform-browser.js:367 ChildActivationStart {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ActivationStart
platform-browser.js:367 ActivationStart(path: '')
platform-browser.js:367 ActivationStart {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ChildActivationStart
platform-browser.js:367 ChildActivationStart(path: '')
platform-browser.js:367 ChildActivationStart {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ActivationStart
platform-browser.js:367 ActivationStart(path: '')
platform-browser.js:367 ActivationStart {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: GuardsCheckEnd
platform-browser.js:367 GuardsCheckEnd(id: 2, url: '/', urlAfterRedirects: '/public', state: Route(url:'', path:'') { Route(url:'public', path:'public') { Route(url:'', path:'') { Route(url:'', path:'') } } } , shouldActivate: true)
platform-browser.js:367 GuardsCheckEnd {id: 2, url: "/", urlAfterRedirects: UrlTree, state: RouterStateSnapshot, shouldActivate: true}
platform-browser.js:380 Router Event: ResolveStart
platform-browser.js:367 ResolveStart(id: 2, url: '/', urlAfterRedirects: '/public', state: Route(url:'', path:'') { Route(url:'public', path:'public') { Route(url:'', path:'') { Route(url:'', path:'') } } } )
platform-browser.js:367 ResolveStart {id: 2, url: "/", urlAfterRedirects: UrlTree, state: RouterStateSnapshot}
platform-browser.js:380 Router Event: ResolveEnd
platform-browser.js:367 ResolveEnd(id: 2, url: '/', urlAfterRedirects: '/public', state: Route(url:'', path:'') { Route(url:'public', path:'public') { Route(url:'', path:'') { Route(url:'', path:'') } } } )
platform-browser.js:367 ResolveEnd {id: 2, url: "/", urlAfterRedirects: UrlTree, state: RouterStateSnapshot}
platform-browser.js:380 Router Event: ActivationEnd
platform-browser.js:367 ActivationEnd(path: '')
platform-browser.js:367 ActivationEnd {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ChildActivationEnd
platform-browser.js:367 ChildActivationEnd(path: '')
platform-browser.js:367 ChildActivationEnd {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ActivationEnd
platform-browser.js:367 ActivationEnd(path: '')
platform-browser.js:367 ActivationEnd {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ChildActivationEnd
platform-browser.js:367 ChildActivationEnd(path: 'public')
platform-browser.js:367 ChildActivationEnd {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ActivationEnd
platform-browser.js:367 ActivationEnd(path: 'public')
platform-browser.js:367 ActivationEnd {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: ChildActivationEnd
platform-browser.js:367 ChildActivationEnd(path: '')
platform-browser.js:367 ChildActivationEnd {snapshot: ActivatedRouteSnapshot}
platform-browser.js:380 Router Event: NavigationEnd
platform-browser.js:367 NavigationEnd(id: 2, url: '/', urlAfterRedirects: '/public')
platform-browser.js:367 NavigationEnd {id: 2, url: "/", urlAfterRedirects: "/public"}
It's essentially exactly the same except for the initial Navigated to value.