Angular Advance Router Configuration
Do you know about the below feature of medium???
Let’s get started !
All of us use Routing as part of one or the other application to allow the user to navigate from one page to another via routes. Angular comes with a default solution known as RouterModule for implementing Routing in the application.
RouterModule is very simple to use and add in your application. In a minimal approach, it's just a import in modules of your application with the routes you want to have and their respective components. For eg :-
@NgModule({
imports: [RouterModule.forRoot(routes)]
})
export class AppModule{}
export const routes: Routes = [
{
path: 'home',
component: HomeComponent
},
{
path: 'logout',
component: LogoutComponent
}
];
So above we used the router module in app module imports and gave it an array of routes and now your routes can be used to reach those components considering you have a router-outlet tag in the app component template. But we also see the use of the forRoot method, So let’s the interface of RouterModule to see different methods available with RouterModule.
class RouterModule {
static forRoot(routes: Routes, config?: ExtraOptions): ModuleWithProviders<RouterModule>
static forChild(routes: Routes): ModuleWithProviders<RouterModule>
}
So Its only two methods that are available i.e. forRoot and forChild. From the definition we can see that forRoot accepts two parameters i.e. routes and an optional config object and forChild only accepts routes.
forRoot is generally used in the root module of your application because it registers the providers/directives/router service etc. required by RouterModule.
forChild is used to define routes for other modules like lazy loaded modules. The only difference is that it doesn’t re-register the router service.
What we will be discussing here is the second config object in the forRoot method. As it allows us to achieve various things via the routes which we might want to use. So let's see its interface first i.e. ExtraOptions.
interface ExtraOptions {
enableTracing?: boolean
useHash?: boolean
initialNavigation?: InitialNavigation
errorHandler?: ErrorHandler
preloadingStrategy?: any
onSameUrlNavigation?: 'reload' | 'ignore'
scrollPositionRestoration?: 'disabled' | 'enabled' | 'top'
anchorScrolling?: 'disabled' | 'enabled'
scrollOffset?: [number, number] | (() => [number, number])
paramsInheritanceStrategy?: 'emptyOnly' | 'always'
malformedUriErrorHandler?: (error: URIError, urlSerializer: UrlSerializer, url: string) => UrlTree
urlUpdateStrategy?: 'deferred' | 'eager'
relativeLinkResolution?: 'legacy' | 'corrected'
}
Let’s discuss these, one by one.
- enableTracing
When this flag is true, angular logs all internal navigation events to the console like when the router is activated when navigation started when navigation did end etc. Its quite useful for debugging while facing issues with routing configuration.
2. useHash
This flag helps in a very specific case. So let’s take a scenario, you have a angular application deployed on tomcat server. You have a route in your Angular application i.e. /dashboard. Now you hit www.abc.com/dashboard in browser. What happens in this case is that browser go to server and server starts checking for this URL and returns 404 (Not Found) because this URL was not present on server as this was a Angular route. So there are two ways to resolve this i.e :- Configure your server to return index.html in these cases or use the useHash strategy.
What useHash does is that your URL will now become www.abc.com/#/dashboard. Now when you will hit the URL the browser doesn’t send the URL after that hash and now you will be served index.html and then angular will take care of that dashboard route. But configuring a server is a better approach in this case. Because # is also used for anchorScrolling which we will cover in next point.
3. anchorScrolling
When set to ‘enabled’, scrolls to the anchor element when the URL has a fragment. Anchor scrolling is disabled by default. What that means is when you will now hit dashboard route the page will be moved to focus this anchor tag wherever its location is on your page. You must have came across web pages where all the content is on same page but by URL they take you to specific section. By this technique you can achieve the same in Angular.
<a [routerLink]='"."' [fragment]="dashboard">Dashboard</a>
4. initialNavigation
When set to enabled
, the initial navigation starts before the root component is created. The bootstrap is blocked until the initial navigation is complete. This value is required for server-side rendering to work. When set to disabled
, the initial navigation is not performed. The location listener is set up before the root component gets created.
In most of applications this will not be required unless due to a complex scenario more control is required over navigation.
5. errorHandler
ErrorHandler is one of the class which we implement in our application to handle errors globally. One way is to have one handler and check error type in it and handle it accordingly with whatever behavior you wanted to achieve. But let’s say you wanted a separate error handler for router to only handle router specific error so you can have a implementation class of error handler and pass it to errorHandler property like below.
class RouterErrorHandler implements ErrorHandler {
handleError(error: any) {
console.log('Router Error Occured');
//handling logic here
}
}
@NgModule({
imports: [RouterModule.forRoot(routes, {errorHandler: RouterErrorHandler})]
})
export class AppModule{}
6. preloadingStrategy
Preloading strategy basically helps in configuring a strategy if you want to preload your lazy loaded modules before the user navigates to route. Angular providers two strategies in-built which are PreloadAllModules or NoPreloading (the default). You can find number of articles for making a custom preloading strategy and pass it to this attribute.
7. onSameURLNavigation
Try one thing, try to navigate to same url in your angular application by router.navigate which is currently activated. You will see that angular ignores this and do not reactivate that route. It is because this property have default value as ignore, if you pass it value as reload then this behavior will change and your route will be reactivated.
8. scrollPositionRestoration
Let’s say user was at some scroll position when was on a page then he navigates to other page. Now he presses back button in browser and you want the scroll position to be same where he left. One way is to write code it by yourself. But angular gives us this property to configure the same. It accepts following values.
- ‘disabled’- (Default) Does nothing. Scroll position is maintained on navigation.
- ‘top’- Sets the scroll position to x = 0, y = 0 on all navigation.
- ‘enabled’- Restores the previous scroll position on backward navigation, else sets the position to the anchor if one is provided, or sets the scroll position to [0, 0] (forward navigation). This option will be the default in the future.
You can also have a custom scroll restoration behavior which you can find in the official documentation.
9. scrollOffset
Configures the scroll offset the router will use when scrolling to an element.
When given a tuple with x and y position value, the router uses that offset each time it scrolls. When given a function, the router invokes the function every time it restores scroll position.
10. paramsInheritanceStrategy
Defines how the router merges parameters, data, and resolved data from parent to child routes. By default (‘emptyOnly’), inherits parent parameters only for path-less or component-less routes. Set to ‘always’ to enable unconditional inheritance of parent parameters.
11. malformedUriErrorHandler
Let’s say you want to achieve a particular behavior if user enters invalid character sequences in the url which causes encodeURI to fail. Angular have a default behavior to that which is to route to root URL and loose all the parameters. You can pass a function to this property to achieve a custom behavior overriding the default one. That function will receive three arguments i.e.
- URIError — Error thrown when parsing a bad URL.
- UrlSerializer — UrlSerializer that’s configured with the router.
- url — The malformed URL that caused the URIError
In your function on the basis of these three parameters you can perform various activities to achieve desired behavior.
12. urlUpdateStrategy
Defines when the router updates the browser URL. By default (‘deferred’), update after successful navigation. Set to ‘eager’ if prefer to update the URL at the beginning of navigation. Updating the URL early allows you to handle a failure of navigation by showing an error message with the URL that failed.
13. relativeLinkResolution
Enables a bug fix that corrects relative link resolution in components with empty paths. Example:
Let’s say you had this routing configuration :-
const routes = [
{
path: '',
component: HomeComponent,
children: [
{ path: 'first', component: FirstComponent },
{ path: 'second', component: SecondComponent },
]
}
];
Now in your HomeComponent template you had following anchor tag
<a [routerLink]="['./first']">Link to First</a>
This will not work as default value of this field is legacy to support backward compatibility. In legacy to make it work you had to use anchor tag like below.
<a [routerLink]="['../first']">Link to First</a>
To enable the fix and use it like ./ instead of ../ you can give this option the value as ‘corrected’ to enable the fix.
These options allows us to handle most of the common scenarios that we might face in any web application. If we don’t know them we might end up writing a custom implementation which will be like re-inventing the wheel. Hence knowing them is very important and adds one more feather to your hat of expertise in Angular.
Hope this helps, and wish you achieve more in your application with these options.