Concept

Read through this chapter in order to understand our way of thinking and coming up with @ng-frrri/router-middleware.

1. States registry

Synopsis

Every application state is a deeply nested object. Therefore it should be possible to access a state's facade by providing a path to its state from root.

If we find a way to expose facades via paths, we can make any interaction highly customisable. Because dependency injection is now delegated to the StatesRegistry, we can easily use facades anywhere in our app.

import { StatesRegistryService } from './states-registry.service';

const statesRegistry = new StatesRegistryService();
const notesFacade = statesRegistry.getByPath<'notes'>('entities.notes');
const usersFacade = statesRegistry.getByPath<'users'>('entities.users');

console.log(notesFacade.getOne(1));
// outputs: { id: 1, title: "Note #1", userId: 1 }

console.log(usersFacade.getOne(1));
// outputs: { id: 1, name: "Josef" }

What are the benefits?

1.1. Smart-ui

The StatesRegistry makes it possible to write general purpose smart-ui components that provide logic used by multiple entities. Imagine you were to write a smart ui component that can be consumed simply by providing a path to the entity's root state:

Ready to use smart components are provided to you in @ng-frrri/ui

For this example, we assume your facades exposes observables named all$ and loading$

<h1>All Notes</h1>

<smart-ui path="entities.notes" #notes>
    <div data-loading>
        Loading posts...
    </div>
    
    <div *ngFor="let note of notes.all$ | async">
        {{ note | json }}
    </div>
</smart-ui>

<h1>All Users</h1>

<smart-ui path="entities.users" #notes>
    <div data-loading>
        Loading notes...
    </div>
    
    <div *ngFor="let user of users.all$ | async">
        {{ user | json }}
    </div>
</smart-ui>

1.2. Router middleware

Mapping facades to paths and exposing them via a StatesRegistry is essential for our RouterMiddleware concept to work (which we will explain next). There are many use cases for the StatesRegistry in enterprise applications that you will find. But let's focus on what @ng-frrri does for you and continue with router middleware.

2. Router middleware

Router middleware is, like the name says, a middleware for the Angular router. Within this middleware you can define operators that run on certain platforms. You can think of those operators like RxJs operators. In fact, they are Observables and they are meant to compute async tasks during the lifecycle of a route. Let’s take a look at the main parts of this concept.

2.1. Operators

An operator defines the nature of the operation that you want to get done on a certain platform of your route. This lib ships with a few predefined operators that fit our initial needs when implementing this package. You can easily extend the set of available operators by creating your own.

2.2. Platforms

Each operator runs on predefined platforms that describe when an operator should be applied during the lifecycle of an Angular route. For now, 3 platforms are available:

  • NavigationEnd: Operation runs at the end of route activation (at ActivationEnd).

  • Resolver: Operation runs as a resolver of your route.

  • Deactivated: Operation runs when route was deactivated (after canDeactivate).

It is important to know that there can be run multiple operations per Platform. They will be executed one after another.

2.3. Middlewares

By extending MiddlewareFactory, you have an entry point to simply switch case your operators. No matter if operations work with state management, api requests or file operations. It is very straight forward to write an adapter for whatever kind of task you want to get done.

To see a practical example of an adapter like this, take a look at NgxsRouterMiddleware which acts as adapter to an @ngxs/store with a CRUD service.

Last updated