dev_054
dev_054

Reputation: 3728

Restrict routes using custom matcher

I have the following route configuration:

const routes: Routes = [
  {
    component: MyComponent,
    path: '',
    children: [
      {
        component: MyListComponent,
        path: ''
      },
      {
        component: MyFormComponent,
        path: ':id/edit'
      },
      { path: '**', redirectTo: '' }
    ]
  }
];

In order to limit the parameters as numbers, I started to search and after spend toooooooooo much time, I've found a way in this closed (I don't know why) issue: https://github.com/angular/angular/issues/12442

So, I changed my config (especifically the part that matters) to the following:

{
  component: MyFormComponent,
  matcher: ComplexUrlMatcher('id', /[1-9]+\/edit/)
}

export function ComplexUrlMatcher(paramName: string, regex: RegExp) {
    return (
        segments: UrlSegment[],
        segmentGroup: UrlSegmentGroup,
        route: Route) => {

        const parts = [regex];
        const posParams: { [key: string]: UrlSegment } = {};
        const consumed: UrlSegment[] = [];

        let currentIndex = 0;

        for (let i = 0; i < parts.length; ++i) {
            if (currentIndex >= segments.length) {
                return null;
            }
            const current = segments[currentIndex];

            const part = parts[i];
            if (!part.test(current.path)) {
                return null;
            }

            posParams[paramName] = current;
            consumed.push(current);
            currentIndex++;
        }

        if (route.pathMatch === 'full' &&
            (segmentGroup.hasChildren() || currentIndex < segments.length)) {
            return null;
        }

        return { consumed, posParams };
    }
}

Source: https://gist.github.com/matanshukry/22fae5dba9c307baf0f364a9c9f7c115


It's almost working. If I go to a route like this:

my_path/1

... it works, but what I want is:

my_path/1/edit

How can I fix this function to make it work?

Upvotes: 13

Views: 2188

Answers (1)

hagner
hagner

Reputation: 1050

You will need to keep on nesting childcomponents in your router to make this function work out of the box. The following works for me with router version 4 and it will only allow the id parameters to be one or more numbers, and the action parameter to match the exact word "edit":

const routes: Routes = [
    {
        component: MyComponent,
        path: '',
        children: [
        {
            component: MyListComponent,
            path: ''
        },
        {
            matcher: ComplexUrlMatcher("id", /[0-9]+/),
            component: MyFormComponent,
            {
                matcher: ComplexUrlMatcher("action", /(edit)/),
                component: MyFormEditComponent,
            }
        },
        { path: '**', redirectTo: '' }
        ]
    }
];

If using child component does not work for you, you will have to rewrite some of the regex logic to match your needs.

Upvotes: 4

Related Questions