58

I am a newbie in Angular 2. I want to create isolated modules for every part of my app. For example I created the AuthModule with default component - AuthComponent which contain a router-outlet for his child components (SignIn or SignUp). So I want to realise the following scenario:

  1. When navigate to / - root off app - redirect to /auth
  2. After redirect to /auth - load AuthComponent with router outlet
  3. After AppComponent loaded - load default sign-in component via redirecting to /auth/sign-in

But when I going to localhost/ I get redirect to /auth what I want, but the next redirect to sign-in doesn't appear.

My code: app.routing

const routes: Routes = [
  {
      path: '', 
      redirectTo: '/auth', 
      pathMatch: 'full'
  }
];

export const appRouting: ModuleWithProviders = RouterModule.forRoot(routes);

auth.routing

const routes: Routes = [
  {
    path: 'auth',
    component: AuthComponent,
    children: [
      {
         path: '', 
         redirectTo: 'sign-in', 
         pathMatch: 'full'
      },
      {
         path: 'sign-in', 
         component: SignInComponent
      }
    ]
  },

];

export const authRouting: ModuleWithProviders = RouterModule.forChild(routes);

auth.component.html

<div class="container">
    <h1>Auth component</h1>
    <router-outlet></router-outlet>
</div>

Result:

code

result

Environment @angular/cli: 1.0.0-rc.2 node: 7.7.1 os: win32 x64

Rich
  • 3,928
  • 4
  • 37
  • 66
Timofey Orischenko
  • 1,148
  • 1
  • 9
  • 12

7 Answers7

51

I have been the same problem. It seems an Angular tricks: If you remove leading slash in 'redirectTo' field, your application will be redirected successfully to auth/sign-in.

Use this in app.routing:

const routes: Routes = [ 

    {path: '', redirectTo: 'auth', pathMatch: 'full'}, 

];

‘redirectTo’ value starts with a ‘/’ = absolute path

‘redirectTo’ value starts without a ‘/’ = relative path

Read more about it: https://vsavkin.com/angular-router-understanding-redirects-2826177761fc

P.S My opinion that your structure more correctly then YounesM's one. Parent module can't keep children routes: "app" module don't know that "auth" module have children module "sign-in".

Lasitha Yapa
  • 4,309
  • 8
  • 38
  • 57
Dmitriy Ivanko
  • 950
  • 8
  • 17
41

On auth.routes

const routes: Routes = [
  {
    path: "auth",
    redirectTo: "auth/sign-in"
  },
  {
    path: "auth",
    component: AuthComponent,
    children: [{ path: "sign-in", component: SignInComponent }]
  }
];
SuleymanSah
  • 17,153
  • 5
  • 33
  • 54
Chema
  • 887
  • 8
  • 14
  • Clever solution. Honestly it never came to my mind that it was possible to duplicate the route configuration! – Lothre1 Apr 26 '20 at 09:50
  • 2
    This seems to break when using lazy loading on feature modules, is there anyway around this? – Ben Black May 01 '20 at 20:58
9

So, what it seems to happen is that when you redirectTo:'auth' it tries to load the '' children's component and since it does not have any component the router-outlet is empty.

Now it seems like {path: '', redirectTo: 'sign-in', pathMatch: 'full'} doesn't have any other purpose then redirecting to sign-in so you can simply redirect to /auth/sign-in instead.

app.routes

const routes: Routes = [
  {path: '', redirectTo: '/auth/sign-in', pathMatch: 'full'}
];
export const appRouting: ModuleWithProviders = RouterModule.forRoot(routes);

auth.routes

const routes: Routes = [
  {
    path: 'auth',
    component: AuthComponent,
    children: [
      {path: 'sign-in', component: SignInComponent}
    ]
  },

];

or have a component in your '' path instead of redirecting.

app.routes

const routes: Routes = [
  {path: '', redirectTo: '/auth', pathMatch: 'full'}
];
export const appRouting: ModuleWithProviders = RouterModule.forRoot(routes);

auth.routes

const routes: Routes = [
  {
    path: 'auth',
    component: AuthComponent,
    children: [
      {path: '', component: SignInComponent}
    ]
  },

];
Kabb5
  • 3,760
  • 2
  • 33
  • 55
YounesM
  • 2,279
  • 15
  • 28
  • Thanks for the answer. Yes, I can redirect to /auth/sign-in from app routes directly and it works perfectly. But I don't want to open internal structure of AuthModule (/auth/**sign-in** part of route, for example) You said: _So, what it seems to happen is that when you redirectTo:'auth' it tries to load the '' children's component and since it does not have any component the router-outlet is empty._ but I have a default children router – Timofey Orischenko Mar 18 '17 at 15:23
  • As long as you use `''` route to redirect it seems that your `routerLink`s will not work properly (since they're trying to load the component) the other alternative will be to have a component to load in the `''` route (as edited). I don't see another way to get around it. – YounesM Mar 18 '17 at 15:33
  • Yes, it will work, but in this case we have no possibility to change url to /auth/ **sign-in** I thought there is a best practice to organize routes inside modules in angular 2. Thanks for your answer – Timofey Orischenko Mar 18 '17 at 16:06
3

It's quite simple:

const routes: Routes = [
    { path: '', redirectTo: '/auth/signin', pathMatch: 'full' },
    { path: 'auth', component: AuthComponent, 
        children: [
            { path: 'signup', component: SignupComponent }, 
            { path: 'signin', component: SigninComponent }, 
            { path: 'logout', component: LogoutComponent }
        ]
    },
    { path: '**', redirectTo: '/auth/signin', pathMatch: 'full' }
];
Anh Pham
  • 2,108
  • 9
  • 18
  • 29
2

You can do this in your child route:

const routes: Routes = [
  { path: 'auth', redirectTo: 'auth/signin'},
  {
    path: 'auth',
    component: AuthComponent,
    children: [{ path: 'signin', component: SignInComponent }],
  },
];
papiliond
  • 23
  • 1
  • 4
1

You can use the re-direction in your outer module, like this:

// Root routing module or app.routing.module
const routes: Routes = [
  {path: '', redirectTo: '/auth', pathMatch: 'full'},
  {path: 'auth', redirectTo: '/auth/sign-in', pathMatch: 'full'}
];

// Child routing module or child.routing.module
const routes: Routes = [
 {
   path: 'auth',
   //component: AuthComponent, may not need this as you only need the template
   children: [
     {path: 'sign-in', component: SignInComponent}
   ]
 },
];

You need not to have an empty path '' in your child component in case you want to navigate to this with a proper path

bitscanbyte
  • 650
  • 8
  • 14
0

I have been the same problem, but none of the above answers seems to be a good resolution. In my code , i subscribe to the router events and finally resolve it.

code in AuthComponent's constructor:

  this.router.events.subscribe((e: Event) => {
   if (e instanceof NavigationEnd) {
    this.activeUrl = e.urlAfterRedirects || e.url;
    if (this.activeUrl === '/auth') {
      this.router.navigateByUrl('/auth/sign-in');
    }
   }
  });
hackzfy
  • 141
  • 1
  • 2