The new way to navigate in angular using aop-routing library
Tags: angular, javascript, tutorial, discuss
Published: 2021-01-04 20:39:58

---
title: The new way to navigate in angular using aop-routing library
published: true
description: aop-routing library brings a lot of neat features to navigation and routing in an Angular application
tags: angular, javascript, tutorial, discuss
---
This article is originally posted on medium [The AOP-Routing library for Angular] (https://medium.com/analytics-vidhya/the-aop-routing-library-for-angular-9ada05f1741d)

There’s an amazing new npm library called [aop-routing](https://www.npmjs.com/package/aop-routing) that enhances and brings a lot of neat features to navigation and routing in an Angular application.

## What exactly is aop-routing?

Taken straight from the documentation: Aop-Routing Provides the capability to perform [Imperative and Popstate navigation](https://medium.com/analytics-vidhya/angular-routing-imperative-vs-popstate-7d254b495c54) operations in Angular through the ease of typescript decorators, without the need to inject or import the Angular Router object.

To sum it up, the aop-routing library allows you to perform navigation between components without having to import or inject the Router object into your component and also provides other neat features such as dynamically updating the routing table at runtime. To perform navigation is as easy as putting a decorator at the top of a method, that’s it!


### Below are the list of features the aop-routing provides:

* Imperative navigation using decorators
* PopState navigation using decorators
* Custom navigation logic to override default navigation logic
* Dynamically add new path to routing table at runtime
* Dynamically change the component of a path at runtime
* Dynamically add/remove CanActivate guards at runtime

Let’s see how we can install and integrate this library into our application
```diff
- Note: The aop-library requires angular version 8.1 or higher to be installed!
```

* Install the aop-routing library to your angular application
npm install aop-routing
```
npm install aop-routing
```
* After installing the library add AopRoutingModule to the top level/root module import array of your application.
```javascript
imports: [
   ...
    AopRoutingModule
  ]
```
* Add AopNavigationService dependency into your top level/root module constructor.

```javascript
export class AppModule {
  constructor(private navigationService: AopNavigationService) {}
 }
```

That’s pretty much all that’s required to integrate the aop-routing library to your angular application.

Now let’s see how we can use the aop-routing library and it’s cool features!

**I will be using the below Routing Table for demonstrating the features**

```javascript
const routes: Routes = [
{path: 'page1', component: Page1Component, canActivate: [TestGuard,]},
{path: 'page2', component: Page2Component },
{path: 'page3', component: Page3Component }
];
```
#### **Routing to a next page**:

With the aop-routing library, when you need to route to a next page or component, it’s as easy as using the **RouteNext()** decorator on top of the function you want to perform the navigation.

Below example will route to page2 at the end of execution of the testMethod1 — **Note there is no injection or usage of the Router Object**.

```javascript
import { Component} from '@angular/core';
@Component({
...
})
export class Page1Component {
constructor() {}
@RouteNext('page2')
public testMethod1() {
...some logic...
 }
}
```
If your navigation is based on dynamic data, this can also be achieved by making your method return a **‘string’** or an **‘AopNavigator’** object. The decorator will use the return value to perform the routing.

```javascript
//Routing dynamically with RouteNext Decorator by returning a string
import { Component} from '@angular/core';
@Component({
...
})
export class Page1Component {
constructor() {}
@RouteNext()
public testMethod1(): string {
...some logic...
return 'page2';
 }
}
-----------------------------------------------------------------
// Routing dynamically with RouteNext Decorator by returning an 
// AopNavigator
import { Component} from '@angular/core';
@Component({
...
})
export class Page1Component {
constructor() {}
@RouteNext()
public testMethod1(): string {
  ...some logic...
  const obj: AopNavigator = {
     destinationPage: 'Test2',
   };
  return obj;
 }
}
```

The aop-routing also has decorators with suffix of **Async** (eg. **RouteNextAsync**), that can be used with asynchronous methods.

```javascript
// The RouteNextAsync decorator will route to page2 by subscribing // to testMethod1 and using it's string value to perform the routing
@RouteNextAsync()
public testMethod1(): Observable<string> {
  ...some logic...
  return of(1, 2, 3).pipe(
   switchMap(x => {
     return of('page2');
   })
 );
}
----------------------------------------------------------------
// The RouteNextAsync decorator will route to page2 by subscribing // to testMethod1 and using the returned AopNavigator object value // to perform the routing
@RouteNextAsync()
public testMethod1(): Observable<AopNavigator> {
  ...some logic...
  
   const obj: AopNavigator = {
    destinationPage: 'Test2',
  };

  return of(1, 2, 3).pipe(
   switchMap(x => {
     return of(obj);
   })
 );
}
```

#### Navigating back
**RouteBack** and **RouteBackAsync** decorators that can be used to perform a popstate navigation to the previous page.

```javascript
//testMethod1 will navigate back to previous page after execution
@RouteBack()
public testMethod1() {
 ...some logic...
}
------------------------------------------------------------------- 
//Will navigate to the previous page after the asynchronous //execution of testMethod1
@RouteBackAsync()
public testMethod1() {
 return of(...some async operations).pipe(
 ...rxjs operators...)
}
```

#### Navigate to a specific state in browser history 
aop-routing library also provides the capability of using popstate navigation to route to a specific state in the browser history, by using the **RouteToState** and **RouteToStateAsync** decorators.

```javascript
// Will traverse 2 states backwards of the browser history state 
// equivalent to hitting the browser back button twice
@RouteToState(-2)
public testMethod1() {
 ...some logic...
}
------------------------------------------------------------------
// Will traverse 2 states forward of the browser history state
@RouteToState(2)
public testMethod1() {
 ...some logic...
}
------------------------------------------------------------------
// Will subscribe to the targeted method and use the returned value to traverse 2 states backwards of the browser history state after end of targetted method.
@RouteToStateAsync()
public testMethod1(): Observable<number> {
  ...some logic...
  return of(1, 2, 3).pipe(
   switchMap(x => {
     return of(-2);
   })
 );
}
------------------------------------------------------------------
// Will make the decorator subscribe to the AopNavigator object returned from the targetted method and use the destinationPage property value to perform popstate navigation traversal of the browser history state.
@RouteToStateAsync()
public testMethod1(): Observable<AopNavigator> {
  ...some logic...
  
   const obj: AopNavigator = {
    destinationPage: -2',
  };

  return of(1, 2, 3).pipe(
   switchMap(x => {
     return of(obj);
   })
 );
}
```
**AopNavigator** interface has other optional properties that can be used to enhance the aop-routing navigation.

**destinationPage**: This property can be passed a string or numeric value that can be used for the RouteNext, RouteNextAsync, RouteToState and RouteToStateAsync decorators to perform navigation.

**navigationExtra**: This property takes an Angular NavigationExtras object to allow extra options to modify the Router navigation strategy for RouteNext and RouteNextAsync decorator.
**preprocess**: This property takes a reference function. This function will be executed prior to any navigations performed by the decorators.
**param**: This property will take a value of any type that can be used as parameter(s) for the passed function in the preprocess property.

### **Custom logic**
If you desire to have finer control of the navigation, this can be done also. **The aop-routing library provides the capability for users to provide their own custom implementation to override the default navigation logic.**

This can be accomplished in as easy as 3 steps.

* Create a class that extends the **AopBaseNavigation** abstract class.

```javascript
export class SampleClass extends AopBaseNavigation {}
```
* Implement the required abstract methods of the AopBaseNavigation abstract class.

- goToNextPage()
- goToPreviousPage()
- goToState()

```javascript
export class SampleClass extends AopBaseNavigation {
 public goToNextPage(...) {
  ...custom logic...
}


 public goToPreviousPage(...) {
  ...custom logic...
}

 public goToState(...) {
  ...custom logic...
}
```

* In the top level/root module add the **AopProxyNavigationService** to the providers array and set the useClass to the newly created class

```javascript
@NgModule({
  imports: [
    ...
    AopRoutingModule
  ],
  providers: [{provide: AopProxyNavigationService, useClass: SampleClass}],
})
```

Now the SampleClass will override the default navigation logic. So the decorators will call the methods of the SampleClass instead of the default logic.

### **Dynamic changes**
One of the coolest feature of the aop-routing library is the ability to modify the Routing table on runtime of an application.

**Note**: It is marked on the documentation page that the below features are still in the experimental stage.

To turn on the experimental feature, you need to pass an object with **experimentalNav** property set to true to the **AopRoutingModule forRoot method** to the top level/root module:

```javascript
@NgModule({
  ...
  imports: [
    ...
    AopRoutingModule.forRoot({expirementNav: true})
  ],
  ...
})
```

#### **Add new path to routing table**:
Scenario: Suppose during run time of the application, for a specific flow we want to add new route path object for the application to navigate to. We are going to use the aop-routing library to add a new path during execution of the application to the Routing table created above.

The path will be **page4** and it should route to **Page4Component**:

* Create a **RouteTransform** object and set the path and *component property:
```javascript
const routeTransform: RouteTransform = {
    path: 'page4',
    component: Page4Component
 };
```

* In the RouteNext or RouteNextAsync deocrator of the targetted function, return an **AopNav** object with the **routeTransform** property set.

```javascript
// aop-routing library will use this object and add this new path to
// the routing table at run time and navigate to it.
@RouteNext()
public testMethod() {
  const routeTransform: RouteTransform = {
    path: 'page4',
    component: Page4Component
 };
  return {routeTransform}
}
```

#### **Changing component of a path at runtime**
With aop-routing, we can also change the component of an existing path at runtime. Recall from our Routing table in the previous section, **page1 will route to **Page1Component**.

Suppose we want to change the component at runtime to go to **Page4Component** instead.

```javascript
// aop-routing will override the default component(Page1Componet)  // set for page1 path and instead set attach Page4Component to 
// page1
@RouteNext()
public testMethod() {
  const routeTransform: RouteTransform = {
    path: 'page1',
    component: Page4Component
 };
  return {routeTransform}
}
```

**Add CanActivate guard(s) at runtime**:
We can also add CanActivate guards to a route path at runtime
Below example will add **guard1** and **guard2** to the page2 route path dynamically and route to it.
```javascript
@RouteNext()
public testMethod() {
  const routeTransform: RouteTransform = {
    path: 'page2',
    canActivateGuards: [guard1, guard2]
 };
  return {routeTransform}
} 
```

#### **Removing CanActivate guard(s) at runtime**:
CanActivate guards can also be removed from a route path at runtime. It is the same code as above. The aop-routing library is able to detect and remove If the guards provided exist in the routing table.

#### **Disabling all CanActivate guard(s) at runtime**:
To remove all CanActivate guards associated to a path is the same steps as adding a guard. Instead the canActivateGuards property should be set to an empty array.

```javascript
@RouteNext()
public testMethod() {
  const routeTransform: RouteTransform = {
    path: 'page1',
    canActivateGuards: []
 };
  return {routeTransform}}
```

**Note**: Changes made to the routing table are not persisted. The routing table is reverted back to its pristine state after navigation.

aop-routing library is great tool that greatly enhances and also makes navigation easier for angular developers.

Have you used the aop-routing library yet? Comment below and let me know your thoughts!