npm package: @impactdk/ngx-routing-utils
Description: A compilation of routing utils for Angular
Author: Jacob Overgaard
Latest version: 1.1.4

# ngx-routing-utils

This package is a compilation of different tools to cater to your dynamic routing needs for Angular.

The package contains the following:

# Dynamic Routing Module

### What is it

This is a module that allows your application to register a dynamic route (\*\*) and have it resolved and parsed into a set of components.

This is especially useful with a CMS as backend, where you don't know all routes before runtime.

### What do I get

-   Dynamic Component: It enables you to render any given component with a set of input parameters.
-   InterceptLinks Directive: It parses the innerHTML of an area and catches internal/relative URLs and resolves them within the Angular Router.
-   NoSSR Directive: It marks an area which should not be compiled on the server.

### How do I use it

1. Import the module to your application, preferably as the very last item

```typescript
import { DynamicRoutingModule } from '@impactdk/ngx-routing-utils';

@NgModule({
    imports: [
      ...,
      DynamicRoutingModule
    ],
})
class SomeModule {}
```

2. Create a page resolver that takes the URL and fetches some data from the CMS or otherwise determines the state of the route, e.g. if it's 404 or 500 (preferably you have some sort of page module to handle dynamic pages for this). This resolver resolves into an interface (IPage), which holds some common attributes for pages like title and content. In real world usage, the content attribute is properly an entire object in and of itself, which is most likely outputted by a CMS/backend. Also note the `template` attribute, which is used to reference the page components; this means that your backend should understand which page components are available in order to resolve the correct one.

```typescript
export interface IPage {
    template: string;
    title: string;
    content: string;
    metaDescription?: string;
}

export class PageResolve implements Resolve<IPage> {
    resolve(route: ActivatedRouteSnapshot) {
        return this.http.get<IPage>('/' + route.url);
    }
}
```

3. Declare a page component which will utilise the output from the resolver, handle SEO/metadata and instantiate the Dynamic Component:

```typescript
// Declare your page components
// NB! Make sure that these are registered as entryComponents in your module
// NB! Make sure to have a static reference in your page components to be able to locate them through the `template` property of the IPage interface, i.e. `static ref: string = 'frontpage'`
const pageComponents = [
    FrontpageComponent,
    SubpageComponent,
    ProductListComponent,
    ErrorpageComponent,
];

@Component({
    template: `
        <article>
            <dynamic-component
                [component]="component"
                [inputs]="inputs"
            ></dynamic-component>
        </article>
    `,
})
export class PageComponent implements OnInit {
    component: any;

    inputs: { data?: string } = {};

    constructor(
        private activatedRoute: ActivatedRoute,
        private title: Title,
        private meta: Meta
    ) {}

    ngOnInit() {
        // Read the content from the route snapshot (this 'content' is the name of the resolve)
        let data: IPage = this.activatedRoute.snapshot.data.content;
        if (!data) {
            return;
        }

        // Find the ComponentClass of the desired pageComponent (based on template)
        this.component = pageComponents.find(
            component => component.ref === data.template
        );

        if (!this.component) {
            this.component = ErrorpageComponent;
            data =
                'No matching PageComponent was found - tried using: ' +
                data.template;
        }

        this.inputs['data'] = data.data;

        // SEO-related information extracted from the data object
        this.title.setTitle(data.title);

        if (data.metaDescription) {
            this.meta.addTag({
                name: 'description',
                content: data.metaDescription,
            });
        }
    }
}
```

4. Register a dynamic route to your router and use your new page resolver and page component to receive data

```typescript
const routes: Routes = [
    {
        path: '**',
        component: PageComponent,
        resolve: {
            content: PageResolve,
        },
    },
];
```

5. Provide a routing strategy that prevents reuse of the dynamic components, because you will practically only use the Page Component for all dynamic routes, so you want that to update with every route change.

# Routing Strategies

This package also includes a couple of routing strategies

## No Reuse Strategy

This strategy will prevent reuse of components on all your route paths

```typescript
@import { NoReuseStrategy } from '@impactdk/ngx-routing-utils';

@NgModule({
  providers: [
    ...
    {
      provide: RouteReuseStrategy,
      useClass: NoReuseStrategy,
    }
  ]
})
```

## Optional Reuse Strategy

This strategy grants you the possibility to define on each route path whether it is reusable or not

```typescript
@import { NoReuseStrategy } from '@impactdk/ngx-routing-utils';

@NgModule({
  providers: [
    ...
    {
      provide: RouteReuseStrategy,
      useClass: NoReuseStrategy,
    }
  ]
})

const routes: Routes = [
  {
    path: '**',
    component: PageComponent,
    data: {
      reuse: false
    },
    resolve: {
      content: PageResolve
    }
  }
];
```

# InterceptLinks

You have to enable anchorScrolling in RouterModule to make scrolling to an Id work with routerLink and fragment.
The Angular doucmentation says it will be enabled by default in the future...

```typescript
@NgModule({
    imports: [
        RouterModule.forRoot(routes, {
            scrollPositionRestoration: 'enabled', // ..."This will be default in the future" from angular
            anchorScrolling: 'enabled', // ..."This will be default in the future" from angular
        }),
    ],
})
export class AppRoutingModule {}
```

# Authors

Original idea by Filip Bruun Bech-Larsen (@filipbech)

Adapted by Jacob Overgaard (@jacob87)