Skip to main content
Ben Nadel at InVision In Real Life (IRL) 2019 (Phoenix, AZ) with: Michiel Westerbeek
Ben Nadel at InVision In Real Life (IRL) 2019 (Phoenix, AZ) with: Michiel Westerbeek

Wildcard Routes (**) Can Be Scoped To Route Sub-Trees In Angular 5.1.3

By
Published in Comments (5)

In the Angular router, you can use the wildcard path - ** - as a catch-all route to render things like a "Not Found" view or to redirect the user back to the root of the application. But, from the documentation, and from many of the Angular Router demos that I've seen, one aspect that's usually omitted (or unclear) is that an application can have more than one wildcard route. And, that a wildcard route can be scoped to a sub-tree of an application. As such, I wanted to put together a quick demo to showcase this wildcard route feature in Angular 5.1.3.

Run this demo in my JavaScript Demos project on GitHub.

Most of the code in this Angular 5.1.3 demo is immaterial - it just lays the ground-work for router-outlets and rendered views. The only important part of this application is the Router configuration in the application module:

// Import the core angular services.
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { RouterModule } from "@angular/router";
import { Routes } from "@angular/router";

// Import the application components and services.
import { AppComponent } from "./app.component";
import { AViewComponent } from "./a-view.component";
import { BViewComponent } from "./b-view.component";
import { SubViewComponent } from "./sub-view.component";

// ----------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------- //

var routes: Routes = [
	{
		path: "app",
		children: [
			{
				path: "a",
				component: AViewComponent,
				children: [
					{
						path: "sub",
						component: SubViewComponent
					},

					// This is a WILDCARD CATCH-ALL route that is scoped to the "/app/a"
					// route prefix. It will only catch non-matching routes that live
					// within this portion of the router tree.
					{
						path: "**",
						redirectTo: "/app/a"
					}
				]
			},
			{
				path: "b",
				component: BViewComponent,
				children: [
					{
						path: "sub",
						component: SubViewComponent
					}
				]
			}
		]
	},

	// Redirect from the root to the "/app" prefix (this makes other features, like
	// secondary outlets) easier to implement later on.
	{
		path: "",
		pathMatch: "full",
		redirectTo: "app"
	},

	// This is the WILDCARD CATCH-ALL route that is scoped to the entire application. It
	// will catch any request that is not matched by an earlier route definition.
	{
		path: "**",
		redirectTo: "/app"
	}
];

@NgModule({
	bootstrap: [
		AppComponent
	],
	imports: [
		BrowserModule,
		RouterModule.forRoot(
			routes,
			{
				// Tell the router to use the HashLocationStrategy.
				useHash: true,
				enableTracing: true
			}
		)
	],
	declarations: [
		AppComponent,
		AViewComponent,
		BViewComponent,
		SubViewComponent
	],
	providers: [
		// CAUTION: We don't need to specify the LocationStrategy because we are setting
		// the "useHash" property in the Router module above.
		// --
		// {
		// provide: LocationStrategy,
		// useClass: HashLocationStrategy
		// }
	]
})
export class AppModule {
	// ...
}

As you can see, there are two places in which I am using the wildcard (**) route:

  • In the root of route tree.
  • In the sub-section of the route tree scoped to "/app/a".

The root one redirects the user back to the root of the application. And, the sub-section one redirects the user back to the root of the "/app/a" sub-tree. One thing to note about any use of the "**" catch-all path is that it has to be the only segment in the path - it cannot be a substring of the path:

  • path: "**" // <--- This works.
  • path: "prefix/**" // <--- This DOES NOT work.

That's why I needed the sub-tree "**" to be a child of the "a" parent segment, not a sibling to it.

That said, if we run this demo and navigate to the "/app/c" path, which does not exist in the route configuration, we get the following redirect:

Using the ** wildcard route handler at the root of an Angular 5.1.3. application.

As you can see, when we redirect to the non-existing route "/app/c", the root-level "**" catch-all route matches as the last possible match and then redirects the user back to the root of the application.

Now, if we navigate to a non-existing route within the "/app/a" sub-tree, we get the following redirect:

Using the ** wildcard route-handler in a sub-tree of the router configuration in an Angular 5.1.3 application.

As you can see, this time, the missing route is handled by the "/app/a" level "**" catch-all and redirects us back to the root of the "/app/a" sub-tree, not to the root of the application.

From a modularity stand-point, this makes a lot of sense - as you plug different routing modules into the Angular application, each module should be able to define and handle its own missing-route logic. But, it's a point that is easy to miss when you're reading through the Odyssean tome that is the Angular Router documentation. I've been digging into the router for months now, and this feature only recently became evident to me. So, hopefully this helps others who may have been confused on the matter in Angular 5.1.3.

Want to use code from this post? Check out the license.

Reader Comments

15,848 Comments

@All,

In this post, I talked about this use of "**" as being good for "modularity". But, I broke that modularity by using an absolute path in the redirect:

redirectTo: "/app/a"

This ends-up coupling the feature-module to the overall URL architecture of the application. However, it doesn't have to be this way. In a quick follow-up post, I demonstrate (after just discovering it) that that a "**" catch-all route can use a *relative* redirect:

path: "**"
redirectTo: ""

... read more about it here: www.bennadel.com/blog/3401-wildcard-routes-can-redirect-relative-to-their-urltree-location-in-angular-5-1-3.htm

I wish I had thought to test this yesterday.

1 Comments

I have tried by putting path: "prefix/#" and it is getting redirecting to random link in google is there any way to handle the same

15,848 Comments

@Vaibhav,

I have no idea why you are getting redirected to a random page on Google. It sounds like that might be a browser issue (like maybe you have your browser configured to use "I'm Feeling Lucky" search results and your URL is somehow hooking into that). I've not seen this behavior before.

15,848 Comments

@Johan,

Very cool - glad this was helpful. The Router really does make some powerful strides towards being able to keep modules very encapsulated. There are some rough patches to get through; but, each release of Angular seems to chip away at the issues.

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel