Angular default path for an outlet

1.9k Views Asked by At

Given the following module, how can I create the routes so that when the application loads this module it will route to CComponent and have the AComponent loaded in the named router outlet search-results

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';

import { AComponent } from './a.component';
import { BComponent } from './b.component';
import { CComponent } from './c.component';

@NgModule({
  declarations: [
    AComponent,
    BComponent,
    CComponent
  ],
  imports: [
    BrowserModule,
    RouterModule.forRoot([
      {
        path: '',
        pathMatch: 'prefix',
        component: CComponent,
        children: [
          {
            path: 'a',
            component: AComponent,
            outlet: 'search-results'
          },
          {
            path: 'b',
            component: BComponent,
            outlet: 'search-results'
          }
       ]
    ])
  ],
  providers: [],
  bootstrap: [CComponent]
})
export class AppModule {}

a.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'a-component',
  template: `
      <div class="tabs row">
        <h3 [routerLink]="[{ outlets: { 'search-results': ['a'] } }]" class="tab" routerLinkActive="active">
          A
        </h3>
        <h3 [routerLink]="[{ outlets: { 'search-results': ['b'] } }]" class="tab" routerLinkActive="active">
          B
        </h3>
      </div>
    <router-outlet name="search-results"></router-outlet>
  `
})
export class AComponent {
}

I have tried a number of different things with the routes:

With the above configuration, the page loads, but the AComponent isn't loaded onto the screen.

If I update CComponent to have the following:

export class CComponent {
  constructor(
    private route: ActivatedRoute,
    private router: Router
  ) {
    router.navigate(
      [
        {
          outlets: {
            'search-results': ['a']
          }
        }
      ], { relativeTo: route });
  }
}

Then everything seems to work, but it seems wrong to have to trigger that navigation in the constructor of the parent element.

If I update the child routes and replace { path: 'a', component: AComponent, outlet: 'search-results' } with { path: '', component: AComponent, outlet: 'search-results' }, the router seems to load that component correctly in the outlet, but the routerLinkActive directive doesn't seem to take effect as the active class isn't added to the first h3 and updating the routerLink to outlets: { 'search-results': ['a'] } doesn't allow navigation back to the AComponent after navigating to the BComponent.

I've tried a number of variations on the above all with no success.

Is there a way to configure the routes so that the default route will load CComponent in the main unnamed router-outlet and AComponent in the named search-results router-outlet?

Plunkr

1

There are 1 best solutions below

7
On

Currently, you are defining the child routes to your base route, one of which is /a (the path that loads AComponent into the search-results outlet), but you are not actually going to that path when the application loads. It works when you imperatively navigate to that route in your CComponent (which does get initialized on load).

If you want the application to load initially with the (search-results):a route active, you can use the redirectTo property in your route definition.

In your case, I would pattern match on the initial route (the empty path: '') and redirect to the path with /a loaded, like this:

RouterModule.forRoot([
      /* this line will match the initially loaded route and 
       immediately redirect to the child route 'a', which loads 
       `AComponent` into the `search-results` outlet */
      { path: '', pathMatch: 'full', redirectTo: '(search-results:a)'},

      {
        path: '',
        pathMatch: 'prefix',
        component: CComponent,
        children: [
          {
            path: 'a',
            component: AComponent,
            outlet: 'search-results'
          },
          {
            path: 'b',
            component: BComponent,
            outlet: 'search-results'
          }
       ]
      }
    ])

Note that order matters in the snippet above. It will match the empty path, redirect to the child route, and the load the component you want in the designated outlet (as you defined in your code).