4

I want to configure route for my angular2 application. My URL needs to be like this:

http://domain_name/constant_value/variable_value/constant_value

The url can be like following examples:

http://localhost/myhouse/floor1/mirror

http://localhost/myhouse/floor1/room1/mirror

http://localhost/myhouse/floor1/room1/bathroom/mirror

Here the routes /myhouse and /mirror are constant. But the middle part can be anything like /floor1 or /floor2/something/something/....

How can i define a route for that in routing module.

const routes: Routes = [
    {
        path: 'myhouse',
        children: [
            {
                path: ..., //here how do i configure it
                children: [
                    {
                        path: '/mirror',
                        component: MirrorComponent            
                    }
                ]
            }
        ]
    }
];

Here the mirror component must be loaded if the url has /mirror at the end of the url if not login component should be loaded. Mirror will be loaded for the urls shown above. Each mirror component will have different propertise value inside according to the variable part of the url.

For login component url will be like:

http://localhost/myhouse

or

http://localhost/myhouse/floor1

or

http://localhost/myhouse/floor1/bathroom1

I tried wanted to use regex but it seems the regex is not supported for newer version of angular2. If I am wrong on not being able to use regex please kindly point me to that direction with an example. If not please point me to right direction.

kanra-san
  • 469
  • 6
  • 9
  • 21

5 Answers5

8

You could use a UrlMatcher by providing matcher key for a Route. Unfortunately it's undocumented for now, so you may need to check the source of router/src/config.ts:

/**
 * @whatItDoes Represents the results of the URL matching.
 *
 * * `consumed` is an array of the consumed URL segments.
 * * `posParams` is a map of positional parameters.
 *
 * @experimental
 */
export type UrlMatchResult = {
  consumed: UrlSegment[]; posParams?: {[name: string]: UrlSegment};
};

/**
 * @whatItDoes A function matching URLs
 *
 * @description
 *
 * A custom URL matcher can be provided when a combination of `path` and `pathMatch` isn't
 * expressive enough.
 *
 * For instance, the following matcher matches html files.
 *
 * ```
 * function htmlFiles(url: UrlSegment[]) {
 *  return url.length === 1 && url[0].path.endsWith('.html') ? ({consumed: url}) : null;
 * }
 *
 * const routes = [{ matcher: htmlFiles, component: HtmlCmp }];
 * ```
 *
 * @experimental
 */
export type UrlMatcher = (segments: UrlSegment[], group: UrlSegmentGroup, route: Route) =>
UrlMatchResult;

This basically allows you to write a function that can do any kind of matching, including regular expressions.

It's still experimental, so there aren't many examples around, but github/matanshukry has kindly provided a gist example of ComplexUrlMatcher. It should give you an idea how to implement one that suits your needs (sadly there's no license, so you can't use it as-is).

user1338062
  • 11,939
  • 3
  • 73
  • 67
  • The `UrlMatcher` and `UrlMatchResult` types are now exported and documented. (See [this commit](https://github.com/angular/angular/commit/578bdeb5223432b300934f36f2cc9c4c566de39a). However, they're still marked as experimental. – Gary McGill Nov 22 '18 at 11:06
1

Try to do that:

const routes: Routes = [
    {
        path: 'myhouse',
        children: [
            {
                path: ':name', //FOR VARIABLE VALUE
                children: [
                    {
                        path: 'mirror', //REMOVE SLASH
                        component: MirrorComponent            
                    }
                ]
            }
        ]
    }
];

Here you will find a better explanation: http://vsavkin.tumblr.com/post/146722301646/angular-router-empty-paths-componentless-routes

Marcel
  • 2,810
  • 2
  • 26
  • 46
  • I tried to use your method but it seems that param can only take one level of variable value(param) of the url. For example it will be ok if i try to access `http://localhost/myhouse/floor1/mirror` but i wont be able to access: `http://localhost/myhouse/floor1/room1/mirror` or `http://localhost/myhouse/floor1/room1/...../....../mirror` the part between /myhouse and /mirror is dynamic and can be of any length such as `/first/second/third/fourth/..........` – kanra-san Feb 09 '17 at 09:44
1

Late to answer but If you still have the same issue here's how I solved the same problem..

This is my route

{
    path: 'myhouse',
    component: MyParenthouseComponent,
    children : [{
        path: '**',
        component: MyhouseComponent
    }]
}

I have defined myhouse as parent route and defined a ** child route to it. Parent component MyParenthouseComponent holds a <router-outlet></router-outlet> as template, nothing else.(If you need anything else it's upto you)

IN my MyhouseComponent ngOnInit I am doing simply this

_router.events.subscribe((val) => {
    console.log(val);
    if(val instanceof NavigationEnd) {
        var url = this._router.url;
        //do anything with url
    }
});

imported routes like this

import { Router, ActivatedRoute, ParamMap, NavigationStart, NavigationEnd } from '@angular/router';

This will get me the current route

For example in case of this route

http://localhost/myhouse/floor1/room1/bathroom/mirror

it will give me

/myhouse/floor1/room1/bathroom/mirror

You can easily manipulate this url for your use.

Rakesh Chand
  • 3,105
  • 1
  • 20
  • 41
  • 1
    what you are basically doing is mapping the `MyhouseComponent` for whatever comes after the parent path `/myhouse` like `/myhouse/**` but what i need is `/myhouse/**/mirror` should map to `MyhouseComponent`. Your solution will show `MyhouseComponent` even if i give `/myhouse/whatever/whatever` in route. What i need is the last part of the route deciding the component to be shown. Like `/myhouse/**/mirror` will show `MymirrorComponent` and `/myhouse/**/bathtub` will show `MybathtubComponent` – kanra-san Aug 11 '17 at 11:46
  • In that case you need to create routes for all cases. Or use this method and do stuff in NgOnInit to check if last node is matching or not using regex or something – Rakesh Chand Aug 11 '17 at 11:49
  • I had similar problem but I didn't know what whould be limit in `shop/**` for `**`, IN your case it looks like you have limit in this case – Rakesh Chand Aug 11 '17 at 11:52
  • yeah that is what i am asking in this question how do i create routes for all such cases in my routing module. i want anything in the middle but the route should recognize the last part. if i define a child route for `/myhouse/**` it will show the same component regardless of the last part. Later solution does work but i have to encapsulate my components in a container component and show according to the values of the last node. – kanra-san Aug 11 '17 at 11:55
  • Do you really have this case ? It looks funny to me. But if that is the case I'll try to answer later today or tomorrow. – Rakesh Chand Aug 11 '17 at 11:58
  • yeah i have constraint on the route. Thanks for the answer, if you know any way to define above behavior in routing module it will be a great help – kanra-san Aug 11 '17 at 11:58
0

Here's how you can solve this.

import { Routes, UrlSegment } from '@angular/router';

const myHouseRouteMatcher =
    (url: UrlSegment[]) => ({ consumed: url.slice(0, -1) });

const routes: Routes = [
    {
        path: 'myhouse',
        children: [
            {
                matcher: myHouseRouteMatcher,
                children: [
                    {
                        path: 'mirror',
                        component: MirrorComponent
                    },
                    {
                        path: 'bathtub',
                        component: BathtubComponent
                    }
                ]
            }
        ]
    }
];
Pang
  • 9,564
  • 146
  • 81
  • 122
Rohan
  • 421
  • 2
  • 7
  • 18
0

I know that you are looking for a regex path values, but there could be another case when based on a given prefix, followed by an unknown URL, you want to do a redirect.

Here I have an example:

const routes: Routes = [
{
    path: 'vacancies', 
    component: VacanciesContainer,
    children: [
        { 
          path: '', 
          component: VacanciesComponent 
        },
        { 
          path: 'create', 
          component: VacancyCreateComponent 
        }
    ]
},
{
    path: 'users', 
    component: UsersContainer,
    children: [
        { 
          path: '', 
          component: UsersComponent 
        },
        { 
          path: 'create', 
          component: UserCreateComponent 
        },
        {
          path: '**',
          redirectTo: '',
          pathMatch: 'full'
        }
    ]
},
{ 
  path: '**', redirectTo: 'vacancies', pathMatch: 'full' 
}];

What does this resolves?

for the URL: /users/something-wrong will be redirected to /users.

for the URL: /something-wrong/something-else will be redirected to /vacancies

Radu Linu
  • 1,143
  • 13
  • 29