Angular 2 Optional Route Parameter

Angular 2 optional route parameter

You can define multiple routes with and without parameter:

@RouteConfig([
{ path: '/user/:id', component: User, name: 'User' },
{ path: '/user', component: User, name: 'Usernew' }
])

and handle the optional parameter in your component:

constructor(params: RouteParams) {
var paramId = params.get("id");

if (paramId) {
...
}
}

See also the related github issue: https://github.com/angular/angular/issues/3525

Angular2+ routing - optional route params

So is there any way to define these type routes with optional params
like we do in ExpressJS

Simple answer is No, you have to define new route for each separate path.

{path: 'users', component: ItemsComponent},
{path: 'users/:filter', component: ItemsComponent}

Though you can verify the path and determine, if it has optional parameter inside the routed component using ActivatedRoute.

Angular routing with optional parameters

To allow the component route to have multiple optional parameters, inside your routing module, specify the route as follows:

const appRoutes: Routes = [
...
{path: 'route1',component: MyComponent}
...
];

In the calling component that you wish to call MyComponent from, use the router navigate() method as follows:

router.navigate(['route1', {p1:value1,p2:value2}]);

Where value1 and value2 are variables within your calling component that
you want to bind to the parameters p1 and p2.

The above should match parameters p1, p2 or p1 and p2 for the route.

In a HTML template, call the above using the following router link:

<a [routerLink]="['/route1', {p1:value1, p2:value2}]" .. />

The router URL link will then resolve to:

/route1;p1=value1;p2=value2

The following router link:

<a [routerLink]="['/route1', {p1:value1}]" .. />

Will resolve to the URL:

/route1;p1=value1

And the following router link:

<a [routerLink]="['/route1', {p2:value2}]" .. />

Will resolve to the URL:

/route1;p2=value2

Note: that if you omit the brackets [] in your router link, then the following error will appear with parameters are included:

Error: Cannot match any routes. URL Segment: ...

Within your component MyComponent, read the parameters using paramMap as follows:

const p1 = this.route.snapshot.paramMap.get('p1');
const p2 = this.route.snapshot.paramMap.get('p2');

The route parameters paramMap are an observable that can change when the same route is called within an application, so it is recommended to subscribe to it within the component as follows:

routingSubscription: Subscription;

constructor(private activatedRoute: ActivatedRoute,
private router: Router) { }

ngOnInit(): void {
let route = this.activatedRoute.snapshot;
let urlSegments = route['_urlSegment'].segments;
let relativePath: string = '';
urlSegments.forEach((pathSegment: UrlSegment) => {
relativePath = relativePath.concat(pathSegment.path, '/');
});

this.routingSubscription = this.activatedRoute.paramMap
.subscribe((params: ParamMap) => {
const firstParam: string = params.get('p1');
const secondParam: string = params.get('p2');

if (firstParam && !secondParam)
{
let mySecondParam: string = "2";
this.router.navigate(
[relativePath, {p1:firstParam,p2:mySecondParam}]);
}
});
}

The example above will allow a route to the component with the first parameter then re-route back with the relative path of the original route. This should also work within a feature module.

Alternatively, the relative path can specified without quantifying the individual path segments in the active route. This can be done using the relativeTo option within router.Navigate().

To make use of relativeTo, import NavigationExtras interface as follows:

import { NavigationExtras } from '@angular/router';

We can then specify and extend the navigation as follows:

this.router.navigate(
[{id1:firstParam,id2:mySecondParam}],
{ relativeTo: this.activatedRoute }
);

Angular - multiple optional route parameters

If you want the language parameter to be the first, you can do the following. You will first have to declare an empty app or whatever root component and use this in the bootstrap instead of the AppComponent:

@Component({
selector: 'app-root',
template: `<router-outlet></router-outlet>`
})
export class RootComponent {}

Then create a module from your current routes, if you do not have that already. Call it AppRoutingModule.

export const AppRoutes: Routes = [      
{ path: 'home', component: HomeComponent },
{ path: 'news', component: NewsComponent },
{ path: 'newsDetail/:id', component: NewsDetailComponent }
];

@NgModule({
imports: [RouterModule.forFeature(AppRoutes)],
exports: [RouterModule],
})
export class AppRoutingModule {}

Then create a RootRoutingModule, which will do the magic:

export const RootRoutes: Routes = [      
{ path: '', loadChildren: () => import('./app.module').then((m) => m.AppModule) },
{ path: 'en', loadChildren: () => import('./app.module').then((m) => m.AppModule) }
];

@NgModule({
imports: [RouterModule.forRoot(AppRoutes)],
exports: [RouterModule],
})
export class RootRoutingModule {}

The issue with this, is that you'll have to hardcode all the languages you might support, as I don't think a :language parameter will work

So basically, create a root module which will do the language routing and the bootstrapping

How to create optional router argument in angular 7

I don't know of a way to make the parameter optional. Depending on what you're trying to achieve you could use a specific string you could detect in the id param (Registration/new vs Registration/678A6).

Anyway the routes are just plain typescript so I guess you could keep it dry this way:

const registrationRouteConfig = {
component: RegisterComponent,
children: [
{ path:'',component:ProfileComponent},
{ path: 'Dependent', component: DependentComponent },
{ path: 'Matrimony', component: MatrimonyComponent },
{ path: 'Subscription', component: MagazinesubscriptionComponent },
{ path: 'Donation', component: DonationComponent }
]
}

const routes: Routes = [
{ path: 'Registration', ...registrationRouteConfig },
{ path: 'Registration/:id', ...registrationRouteConfig },
{ path: 'Profile', component: ProfilelistComponent }
]

Optional Parameters While Routing angular2

You can define multiple routes with and without parameter having the same component:

@RouteConfig([{
path: '/abc',
component: Abc,
name: 'abc'},
{
path: '/abc/:xyz',
component: Abc,
name: 'abcXyz'
}])

and then use the one that you need

<a [routerLink]="['/abcXyz',{xyz: blabla}]">
and
<a [routerLink]="['/abc']">

If routeCongig is located in your root file, use / before root's name and if it's on the second level or something, use

<a [routerLink]="['/parentRoot', {parentParams:value}, '/abc']">

Angular 2: Redirect route with parameters and optional parameters

The angular router basically looks at path objects and creates the set of basic routes of your app (without the optional parameters). Which then would be used to recognise routes if they match the path exactly. So the optional parameters cannot be used inside them because they're "optional". And the only way to include any route params in these path objects, is binding them inside the url with':something' syntax which then wouldn't be optional.
I think you have some other ways to cover this need of yours:

Adding your "mode" parameter to your basic route:
You can define a path like this: { path:'/bar/:id/:mode', component: BarComponent } and change your redirect path to { path: 'foo/bar/:id', redirectTo: '/bar/:id/test' }

Using a proxy component:
Change the redirect path to: { path: 'foo/bar/:id', component: BarProxyComponent } , and define that component like this:

export class BarProxyComponent {
constructor(private _router: Router, private _route: ActivatedRoute){
_router.navigate(['/bar/'+_route.snapshot.params['id'],{mode: 'test'}]);
}
}

Using a canActivate Guard: You can also create a guard service for your 'foo' path, and inside the guard redirect it to the route you want. However, it's not exactly the real intention behind these guards and it's just taking advantage of them for that said problem.
You can change the redirect path to { path: 'foo/bar/:id', component: UnusedFooComponent, canActivate: [FooGuard]} and define the guard like this:

@Injectable()
export class FooGuard implements CanActivate {

constructor(private _router: Router){}
canActivate(route: ActivatedRouteSnapshot) {
this._router.navigate(['/bar/'+route.params['id'],{mode: 'test'}]);
return false;
}
}

Also don't forget to provide the FooGuard at a module level.
And note that here, you're always redirecting to another place (and returning false) in the guard before the UnusedFooComponent is created...



Related Topics



Leave a reply



Submit