Functional programming with the Angular router

How to implement CanActivate and Resolve in a functional style.

David
Sparkles Blog
3 min readApr 7, 2017

--

A minimalistic demo application, with a perfect friday’s evening sunset — stockphoto: https://pixabay.com/en/norway-cruise-sunset-boat-sky-2144784/

To demonstrate the implementation idea, I’ve set up a minimalistic demo application. The source code is available to you on GitHub. Please find the link at the bottom of the story. Now, let’s dive in!

A glance at the classic object-oriented style

The traditional approach in Angular is to implement routing guards as classes. Let’s just take a quick look at that so that we can compare both approaches — object-oriented and functional:

A route guard implemented in classical object-oriented style

The class FooGuard implements the interface CanActivateand the only method defined by that interface, namely canActivate().

The implementation class is annotated with@Injectable()— in TypeScript jargon, the class is actually decorated but it works pretty much the same way as annotations do in other oop languages.

To make things work, the class is hooked into Angular’s dependendency injection and routing framework by its class token. In JavaScript land, FooGuard is a reference to the constructor function and thus we
write canActivate: [ FooGuard ]as well as providers: [ FooGuard ].

Implementation of `CanActivate` in functional programming style

Now, let’s implement the same with a functional approach:

Implementation of the above CanActivate route guard in functional programming style

Here, barGuard() serves as a factory function and returns a lambda expression, a so-called arrow function in TypeScript terms. The call signature of the lambda is equivalent to that defined by the function canActivate() that we have seen before.

The guard implementation must yet be hooked into Angular’s dependency injection. For that purpose, a factory provider will be registered with:

{ provide: BAR_GUARD_TOKEN, useFactory: barGuard }

That token BAR_GUARD_TOKEN is also referenced in the route definition.

When activating the /bar route, Angular resolves the token, executes the factory function, and calls the lambda expression returned by the factory.

The return value of the lambda expression tells the router to either allow (returning true) or deny navigation (returning false). If allowed, a component shows up on the screen telling you that “bar works!”.

Using the guard in a route definition looks a little bit different for the object-oriented and the functional approach. The following code snippet gives us a good understanding and shows how things are wired up:

Route definitions and provider registration for functional route guards

Advanded functional programming with the Angular router

In the same way that CanActivate guards are implemented in functional programming style, it’s also possible to implement Resolve.

Again, write a factory that returns a lambda expression whose call signature is equivalent to resolve()defined by the Resolve interface.

The function needs to registered with Angular’s dependency injection and routing framework by its corresponding token FOOBAR_RESOLVER_ALPHA.

A functional route resolver

In object-oriented style, it’s possible to inject services into CanActivate and
Resolve implementations, since the @Injectable()decorator makes the class eligible for constructor injection.

In functional programming style, we can do the same thing by passing dependencies as arguments to the factory function. This works by altering the factory provider:

{ provide: FOOBAR_RESOLVER_BETA,
useFactory: foobarResolverBeta,
deps: [ RemoteDataService ] }

An instance of RemoteDataService is then injected to the factory function and the lambda-style resolver is going to return data by delegating to the service.

A functional route resolver with dependencies

Like in the first example, the functions need to be registered for Angular’s dependency injection. The relevant code snippet is:

Registering factory providers for route resolver functions

Try it out!

If you like to see the application with your own eyes or just like playing around, here is the source code:

What do you guys think? Do you like the functional programming approach? Do you prefer the object-oriented way? Let me know!

--

--