Passing type-safe route data to routes in angular 2

Viewed 3457

In my routing module I am passing data in this fashion.

const routes: Routes = [
  { path: '', redirectTo: 'login', pathMatch: 'full' },
  { path: 'login', component: LoginComponent, data: { ShowTopBar: true, showSideBar: false} },
  { path: 'error', component: ErrorComponent, data: { ShowTopBar: true, showSideBar: false}}

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

In order to make the data type safe I have created a RouteData class which would hold the ShowTopBar and ShowSideBar values and initialize them through a constructor.

export class RouteData {
constructor(showTopbar: boolean, showSideBar: boolean) {
  this.ShowSideBar = showSideBar;
  this.ShowTopBar = showTopbar;
}
 public ShowTopBar: boolean;
 public ShowSideBar: boolean;
}

Now, I have changed the declarations for Routes in the following manner:

const routes: Routes = [
  { path: '', redirectTo: 'login', pathMatch: 'full' },
  { path: 'login', component: LoginComponent, data: new RouteData(false, false) },
  { path: 'error', component: ErrorComponent, data: new RouteData(true, false)}

];

which is giving the following error on compiling:

Error encountered resolving symbol values statically. Calling function 'RouteData', function calls are not supported. Consider replacing the function or la mbda with a reference to an exported function, resolving symbol AppRoutingModule

My Question is how can we pass RouteData in a type-safe way to Routes so that I can take advantage of type-safety.

3 Answers

you can do below,

extend Route from @angular/router and update Type of data like below,

export interface RouteData {
  ShowTopBar: boolean;
  ShowSideBar: boolean;
}

interface CustomRoute extends Route {
  data?: RouteData;
}

update type of routes to CustomRoute[] from Routes

const routes: CustomRoute[] = [
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  { path: 'home', component: HomeComponent, data: { ShowSideBar: true, ShowTopBar: true } }
];

now you can pass Type safe data, see below,

enter image description here

Extrapolating on Madhu's answer, if you want your entire navigation tree to have those properties, not just the top level routes, you must also override the children property like this:

interface CustomRoute extends Route {
  data?: RouteData;
  children?: CustomRoute[];
}

I had a similar approach to Madhu's but was wondering why my child routes did not have intellisense or type safety. Then I realized the children property was still set to Routes from the framework's definition.

I wrote a small library that covers all typings for the standard router.

ngx-typed-router

It allows you to have types for everything starting from router configuration, components, resolvers and ending with tests.

E.g.

export const ExampleRoutes: Routes = [
  {
    path: 'test/:id',
    component: ExampleComponent,
    resolve: {
      exampleResponse: ExampleResolveService,
    } as ResolveConfig<ExampleTestRouteData>,
  },
];

export interface ExampleTestRouteQuery {
  param1: string;
}

export interface ExampleTestRoutePath {
  id: string;
}

export interface ExampleTestRouteData {
  exampleResponse: ExampleResponse;
}

Component:

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
  styleUrls: ['./example.component.scss']
})
export class ExampleComponent {

  constructor(
    @Inject(ActivatedRoute) public route: TypedRoute<ExampleTestRouteData, ExampleTestRoutePath, ExampleTestRouteQuery>,
    // or 
    // @Inject(ActivatedRoute) public route: TypedRoute<ExampleTestRouteData>,
    // all generic types are defaulting to angular standard types
  ) { }

}

and template:

<div>{{ route.snapshot.data.exampleResponse.id }}</div>
<div>{{ route.snapshot.data.exampleResponse.name }}</div>

All is type-safe and refactorable.

Check the documentation for more examples.

Related