Search code examples
angularangular-routing

AoT and function factory (Dynamic Route Templates)


I'm trying to make an UrlMatcher factory

export const dummyMatcher: UrlMatcher = matchUrlFn(sitemap as any, 'dummy');

export const routes: Routes = [
  { matcher: dummyMatcher, component: DummyComponent },
  { path: '**', component: DummyComponent },
];

But this doesn't work with AoT... How do we handle function factories with AoT?

I tried

export function dummyMatcher(): UrlMatcher { return routeMatcher(sitemap as any, 'dummy'); }

but compiler is complaining:

Type '{ matcher: () => UrlMatcher; component: typeof DummyComponent; }...' is not assignable to type 'Route[]'.


Use case:

I need to match web pages (described in NavigationNode[]) and render them in specific template components. Page can have multiple urls (for migration purposes, localized urls, etc.). Here's the matching logic:

import { UrlSegment, UrlSegmentGroup, Route, UrlMatchResult } from '@angular/router';
import { inArray } from '@core/utils';

export interface NavigationNode {
  ...
  title?: string;
  template?: string;
  urls?: string[];
}

/**
 * https://angular.io/api/router/UrlMatcher
 */
export const UrlMatcherFactory = (conditions) =>
  (segments: UrlSegment[], group: UrlSegmentGroup, route: Route): UrlMatchResult =>
    conditions(segments) ? ({ consumed: segments }) : null;

export const matchUrl = (nodes: NavigationNode[], template?: string) =>
  (segments: UrlSegment[]) => nodes
    .filter(node => template ? node.template === template : true)
    .some(node => inArray(node.urls)(`/${segments.join('/')}`));

export const matchUrlFn= (nodes: NavigationNode[], template?: string) =>
  UrlMatcherFactory(matchUrl(nodes, template));

This can be easily extended to use different matching, for example Regex:

export const matchRegex = (nodes: NavigationNode[]) =>
  (segments: UrlSegment[]) => nodes
    .some(node => /\w+\/xyz/\d{1, 3}/.test(node.title)); /* bad example (: */

export const matchRegexFn = (nodes: NavigationNode[], template?: string) =>
  UrlMatcherFactory(matchRegex(nodes));

Solution

  • matcher property should implement UrlMatcher type:

    export declare type UrlMatcher = (segments: UrlSegment[], group: UrlSegmentGroup, route: Route) => UrlMatchResult;
    

    so i would suggest you to change code like:

    export function dummyMatcher(segments: UrlSegment[], group: UrlSegmentGroup, route: Route): UrlMatchResult {
      const factory = matchUrlFn(sitemap as any, 'dummy');
      return factory(segments, group, route);
    }