Monthly Archives: March 2017

Angular 2 Nested Routing – Demo

Angular 2 routing supports nested routing which was kind of lacking in Angular 1.*, unless you use UI-Router in Angular 1. Nested routing can be achieved in Angular using the Component router, which is pretty powerful and configurable and most of all supports deep nested routing, using the component router, you can declaratively specify application states, manage state transitions while taking care of the URL, and load bundles on demand. This blog post will cover how to set up the nested routing, it includes nesting up to 3 levels, but you can do much deeper nesting as well.

So this demo looks some thing like this

nested-routing-1

nested-routing-2

Essentially we have an app (which is a a component) which has following 2 components (child components)

  • Customers – This component has further child components
    • Customers List
    • Prospect Customers
    • Inquiries
  • Orders – This component has further child components
    • Completed Orders
    • In Progress Orders

Lets looks at first app component and lets set up the Main navigation, here is how the app component html looks like, left is navigation area and right is the router outlet where either orders or customer component will be displayed depending upon the route selection.

router-outlet:  It acts as a placeholder that Angular dynamically fills based on the current router state.

nested-routing-3

In the app module we need to define  the routes, here is how the app module looks like

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { RouterModule, Route } from '@angular/router';
import { CustomersModule } from './customers/customers.module';
import { OrdersModule } from './orders/orders.module';
import { CustomersComponent } from './customers/customers.component';
import { OrdersComponent } from './orders/orders.component';
import { AppComponent } from './app.component';
const appRoutes = [
  {
    path: 'customers',
    component: CustomersComponent,
    loadChildren: './customers/customers.module#CustomersModule',
    data: { preload: true }
  },
  {
    path: 'orders',
    component: OrdersComponent,
    loadChildren: './orders/orders.module#OrdersModule',
    data: { preload: true }

  },
  {
    path: '',
    redirectTo: '/customers',
    pathMatch: 'full',
  },
]
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule, FormsModule, HttpModule, CustomersModule, OrdersModule,
    RouterModule.forRoot(appRoutes)
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

 

As you can see we have defined the routes to load Orders and Customers component as well as redirect to customers component by default in case of empty route path.

Also please note the RouterModule.forRoot(appRoutes),  this configures the routing for root module.

RouterModule can be imported multiple times: once per lazily-loaded bundle. Since the router deals with a global shared resource–location, we cannot have more than one router service active. That is why there are two ways to create the module:

  • RouterModule.forRoot
    • forRoot creates a module that contains all the directives, the given routes, and the router service itself.
  • RouterModule.forChild.
    • forChild creates a module that contains all the directives and the given routes, but does not include the router service.

When registered at the root, the module should be used as RouterModule.forRoot as shown in the app module above. For submodules and lazy loaded submodules the module should be used as RouterModule.forChild as shown below for CustomersModule or OrderModules.

loadChildren is a reference to lazy loaded child routes. In the above case if loadChildren is not specified then when user hits http://localhost:4200 then it routes to http://localhost:4200/customers, and displays the customers component but does not load the child components. When we specify loadChildren then it loads the child component.

For loadChildren Angular will fetch the module at the location and then load the routes defined in its router config. The path to the file and name of the module is separated by #. The Router reads the ModuleName given after # and loads the module accordingly. So we did not load CustomersModule and OrdersModule in our AppComponent, instead used loadChildren property in the routing config to lazy load our modules.

By default it loads customer component in the main area, so lets look at the customer component, here is how the html for customer component looks like

nested-routing-4.JPG

Customers List, Prospect Customers and Inquiries are the bootstrap tabs, clicking on those loads respective component in the router-outlet area.

Here is how the customer module looks like

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Route } from '@angular/router';
import { CustomersComponent } from './customers.component';
import { CustomersListComponent } from './customers-list/customers-list.component';
import { ProspectsComponent } from './prospects/prospects.component';
import { InquiriesComponent } from './inquiries/inquiries.component';
import { CustomersService } from "./customers.service";
const customersRoutes = [
  {
    path: 'customers',
    component: CustomersComponent,
    children: [
      {
        path: '',
        redirectTo: '/customers/list',
        pathMatch: 'full',
      },
      {
        path: 'list',
        component: CustomersListComponent
      },
      {
        path: 'prospects',
        component: ProspectsComponent
      },
      {
        path: 'inquiries',
        component: InquiriesComponent
      }
    ]
  }
]
@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild(customersRoutes)
  ],
  declarations: [CustomersComponent, CustomersListComponent, ProspectsComponent, InquiriesComponent],
  providers: [CustomersService]
})
export class CustomersModule { }

 

Over here we are defining routes to load child components of customers component.

Please note RouterModule.forChild(customersRoutes), this configures the child routes for Customer component.

We are also redirecting to Customers list component by default in case of empty routes. So when user hits the URL http://localhost:4200/ app module routing redirects to http://localhost:4200/customers as well as tells to load child components as mentioned above not in the customers component we have a redirect specified that in case of empty route redirect to ‘/customers/list‘ i.e. http://localhost:4200/customer/list.

Screen shot for customers list is covered above,below one shows child components (Prospect and Inquiries respectively).

nested-routing-5nested-routing-6

Similar to customers component Orders Component has its own child component, here is how the html looks like

nested-routing-7

and its module looks some thing like this

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Route } from '@angular/router';
import { OrdersComponent } from './orders.component';
import { CompletedOrdersComponent } from './completed-orders/completed-orders.component';
import { InProgressOrdersComponent } from './in-progress-orders/in-progress-orders.component';
import { OrdersService } from './orders.service';
const ordersRoutes = [
  {
    path: 'orders',
    component: OrdersComponent,
    children: [
      {
        path: '',
        redirectTo: '/orders/completed',
        pathMatch: 'full',
      },
      {
        path: 'completed',
        component: CompletedOrdersComponent
      },
      {
        path: 'inprogress',
        component: InProgressOrdersComponent
      }
    ]
  }
]
@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild(ordersRoutes)
  ],
  declarations: [OrdersComponent, CompletedOrdersComponent, InProgressOrdersComponent],
  providers: [OrdersService]
})
export class OrdersModule { }

Screen shot for Completed orders is covered above,below one shows in-progress orders child components.

nested-routing-9

Complete source can be found on GitHub