DEV Community

Dankwansere
Dankwansere

Posted on • Edited on

The new way to navigate in angular using aop-routing library

This article is originally posted on medium The AOP-Routing library for Angular

There’s an amazing new npm library called 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 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

- Note: The aop-library requires angular version 8.1 or higher to be installed!
Enter fullscreen mode Exit fullscreen mode
  • Install the aop-routing library to your angular application npm install aop-routing
npm install aop-routing
Enter fullscreen mode Exit fullscreen mode
  • After installing the library add AopRoutingModule to the top level/root module import array of your application.
imports: [
   ...
    AopRoutingModule
  ]
Enter fullscreen mode Exit fullscreen mode
  • Add AopNavigationService dependency into your top level/root module constructor.
export class AppModule {
  constructor(private navigationService: AopNavigationService) {}
 }
Enter fullscreen mode Exit fullscreen mode

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

const routes: Routes = [
{path: 'page1', component: Page1Component, canActivate: [TestGuard,]},
{path: 'page2', component: Page2Component },
{path: 'page3', component: Page3Component }
];
Enter fullscreen mode Exit fullscreen mode

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.

import { Component} from '@angular/core';
@Component({
...
})
export class Page1Component {
constructor() {}
@RouteNext('page2')
public testMethod1() {
...some logic...
 }
}
Enter fullscreen mode Exit fullscreen mode

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.

//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;
 }
}
Enter fullscreen mode Exit fullscreen mode

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

// 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);
   })
 );
}
Enter fullscreen mode Exit fullscreen mode

Navigating back

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

//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...)
}
Enter fullscreen mode Exit fullscreen mode

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.

// 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);
   })
 );
}
Enter fullscreen mode Exit fullscreen mode

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.
export class SampleClass extends AopBaseNavigation {}
Enter fullscreen mode Exit fullscreen mode
  • Implement the required abstract methods of the AopBaseNavigation abstract class.

  • goToNextPage()

  • goToPreviousPage()

  • goToState()

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


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

 public goToState(...) {
  ...custom logic...
}
Enter fullscreen mode Exit fullscreen mode
  • In the top level/root module add the AopProxyNavigationService to the providers array and set the useClass to the newly created class
@NgModule({
  imports: [
    ...
    AopRoutingModule
  ],
  providers: [{provide: AopProxyNavigationService, useClass: SampleClass}],
})
Enter fullscreen mode Exit fullscreen mode

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:

@NgModule({
  ...
  imports: [
    ...
    AopRoutingModule.forRoot({expirementNav: true})
  ],
  ...
})
Enter fullscreen mode Exit fullscreen mode

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:
const routeTransform: RouteTransform = {
    path: 'page4',
    component: Page4Component
 };
Enter fullscreen mode Exit fullscreen mode
  • In the RouteNext or RouteNextAsync deocrator of the targetted function, return an AopNav object with the routeTransform property set.
// 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}
}
Enter fullscreen mode Exit fullscreen mode

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.

// 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}
}
Enter fullscreen mode Exit fullscreen mode

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.

@RouteNext()
public testMethod() {
  const routeTransform: RouteTransform = {
    path: 'page2',
    canActivateGuards: [guard1, guard2]
 };
  return {routeTransform}
} 
Enter fullscreen mode Exit fullscreen mode

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.

@RouteNext()
public testMethod() {
  const routeTransform: RouteTransform = {
    path: 'page1',
    canActivateGuards: []
 };
  return {routeTransform}}
Enter fullscreen mode Exit fullscreen mode

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!

Top comments (0)