Configurable Router Links (DRAFT)
While the route configuration allows the application to listen to different routes, the links to those routes must take the route configuration into account as well.
Configured router links can be automatically generated in HTML templates using cxUrl
pipe. It allows to transform the name of the route and the params object into the configured path
Assumptions and limitations
- the output path array is absolute by default (it contains the leading
'/'
) - the output path doesn’t contain the leading
/
, when the input starts with an element that is not an object withroute
property, i.e. string'./'
,'../'
or{ not_route_property: ... }
- the route that cannot be resolved from a route’s name and params will return the root URL
['/']
Prerequisites
Import UrlModule
in every module that uses configurable router links.
Router links
Transform the name of the route and the params object
{ cxRoute: <route> } | cxUrl
Example:
<a [routerLink]="{ cxRoute: 'cart' } | cxUrl"></a>
when config is:
ConfigModule.withConfig({
routing: {
routes: {
cart: { paths: ['custom/cart-path'] }
}
}
})
result in:
<a [routerLink]="['/', 'custom', 'cart-path']"></a>
The route with parameters
When the route needs parameters, the object with route’s name
and params
can be passed instead of just simple string. For example:
<a [routerLink]="{ cxRoute: 'product', params: { productCode: 1234 } } | cxUrl"></a>
where config is:
ConfigModule.withConfig({
routing: {
routes: {
product: { paths: [':productCode/custom/product-path'] }
}
}
})
result:
<a [routerLink]="['/', 1234, 'custom', 'product-path']"></a>
Links to nested routes
When Angular’s Routes
contain arrays of children
routes:
const routes: Routes = [
{
data: { cxRoute: 'parent' }, // route name
children: [
{
data: { cxRoute: 'child' }, // route name
/* ... */
},
{
data: { cxRoute: 'otherChild' }, // route name
/* ... */
}
],
/* ... */
}
];
then config should be:
ConfigModule.withConfig({
routing: {
routes: {
parent: { // route name
paths: ['parent-path/:param1'],
},
child: { // route name
paths: ['child-path/:param2'],
}
otherChild: { // route name
paths: ['other-child-path'],
}
}
}
})
In order to generate the path of parent and child route we need to pass them in an array. For example:
<a [routerLink]="[
{ cxRoute: 'parent', params: { param1: 'value1' },
{ cxRoute: 'child', params: { param2: 'value2' }
] | cxUrl,
)"></a>
result:
<a [routerLink]="['/', 'parent-path', 'value1', 'child-path', 'value2']"></a>
Relative links
If you are already in the context of the activated parent route, you may want to only generate a relative link to the child route. Then you need to pass './'
string in the beginning of the input array . For example:
<a [routerLink]="[ './', { cxRoute: 'child', params: { param2: 'value2' } } ] | cxUrl"></a>
result:
<a [routerLink]="['./', 'child-path', 'value2']"></a>
Relative links up
If you want to go i.e. one one level up in the routes tree, you need to pass ../
to the array. For example:
<a [routerLink]="[ '../', { cxRoute: 'otherChild' } ] | cxUrl"></a>
result:
<a [routerLink]="['../', 'child-path', 'value2']"></a>
NOTE: Every element that is not an object with route
property won’t be transformed. So for example:
<a [routerLink]="[
{ cxRoute: 'parent', params: { param1: 'value1' } },
'SOMETHING'
] | cxUrl,
)"></a>
will result in:
<a [routerLink]="['/', 'parent-path', 'value1', 'SOMETHING']"></a>
NOTE: If the first element in the array is not an object with route
property, the output path array won’t have '/'
element by default. So for example:
<a [routerLink]="[
'SOMETHING',
{ cxRoute: 'parent', params: { param1: 'value1' } }
] | cxUrl,
)"></a>
will result in:
<a [routerLink]="['SOMETHING', 'parent-path', 'value1']"></a>
Parameters mapping
When properties of given params
object do not match exactly to names of route parameters, they can be mapped using paramsMapping
option in the configuration. For example:
The params
object below does not contain necessary property productCode
, but it has code
:
<a [routerLink]="{ cxRoute: 'product', params: { code: 1234 } } | cxUrl"></a>
Then paramsMapping
needs to be configured:
ConfigModule.withConfig({
routing: {
routes: {
product: {
/* 'productCode' route parameter will be filled with value of 'code' property of 'params' object */
paramsMapping: { productCode: 'code' }
paths: [':productCode/custom/product-path']
}
}
}
})
result:
<a [routerLink]="['/', 1234, 'custom', 'product-path']"></a>
Predefined parameters mapping
The routes of some storefront already have predefined paramsMapping
. They can be found in default-routing-config.ts
.
// default-routing-config.ts
product: {
paramsMapping: { productCode: 'code' }
/* ... */
},
category: {
paramsMapping: { categoryCode: 'code' }
/* ... */
},
/* ... */
Programmatic API
Navigation to the generated path
The RoutingService.go
method called with { cxRoute: <route> }
navigates to the generated path - similar like routerLink
with cxUrl
pipe in the HTML template. For example:
When config is:
ConfigModule.withConfig({
routing: {
routes: {
product: { paths: ['p/:productCode'] }
}
}
})
routingService.go({ cxRoute: 'product', params: { productCode: 1234 } });
// router navigates to ['/', 'p', 1234]
Simply generation of the path
The UrlService.generateUrl
method called with { cxRoute: <route> }
returns the generated path (just like cxUrl
pipe in HTML templates). For example:
When config is:
ConfigModule.withConfig({
routing: {
routes: {
product: { paths: ['p/:productCode'] }
}
}
})
urlService.generateUrl({ cxRoute: 'product', params: { productCode: 1234 } });
// ['/', 'p', 1234]