Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 429
dev_054 Avatar asked Aug 07 '17 02:08

dev_054


People also ask

How do I use a custom url matcher?

A custom URL matcher behaves like any other route definition. Define child routes or lazy loaded routes as you would with any other route. With the custom matcher in place, you now need to subscribe to the route parameters in the profile component. In your code editor, open your profile.component.ts file.

How do I prevent a route from being matched?

A custom route constraint enables you to prevent a route from being matched unless some custom condition is matched. In this tutorial, we create a Localhost route constraint. The Localhost route constraint only matches requests made from the local computer. Remote requests from across the Internet are not matched.

How to match a remote request with a custom route constraint?

Remote requests from across the Internet are not matched. You implement a custom route constraint by implementing the IRouteConstraint interface. This is an extremely simple interface which describes a single method: The method returns a Boolean value. If you return false, the route associated with the constraint won't match the browser request.

How to make a route match the content type of a request?

r.HeadersRegexp ("Content-Type", "application/ (text|json)") ...and the route will match both requests with a Content-Type of application/json as well as application/text There's also a way to build only the URL host or path for a route: use the methods URLHost () or URLPath () instead.


1 Answers

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.

like image 169
hagner Avatar answered Oct 05 '22 10:10

hagner