8

I try to build dynamically routes from angular2 (fetch route config from server), after that I parse it and generate instruction for component route (I have parent routes config and child into different components, because I don`t know how define route for child component into one main.app.ts file).

The problem is when app started and try to create routes config and routeGenerator is not build routes yet (async delay) cant parse routes data (because async delay, so routesData undefined now) and app is crashig. I dont know what to do with this. Looking for lifecycle hood (some like - @Angular2BeforeAppStarted ) but found nothing.

    import {Component, Input, OnChanges} from 'angular2/core';
import {RouteConfig, RouterOutlet, ROUTER_DIRECTIVES, Router} from 'angular2/router';
/* ------- !Angular 2 native components  ---------*/
import {routeGenInstance} from '../../config/routes/patient_routes';


protected const BUILT_MODULE_PATH: string = '/built/modules/patients/';

@Component({
  template: `
    <router-outlet ></router-outlet>
  `,
  directives: [RouterOutlet, ROUTER_DIRECTIVES]
})
@RouteConfig(routeGenInstance.getRouteDefinitions())

export class PatientsComponent {
  @Input();

  constructor() {}

}

Also i try to update routes in the same way (but app is crashed immediately because my Navigation link in navigation component is not have some correct link way)

import {RouteConfig, RouterOutlet, ROUTER_DIRECTIVES, Router} from 'angular2/router';

     constructor(
        private router: Router
         ) {
        router.config([
             routeGenInstance.getRoutesDefinition()
        ])
      }

my route definitions use Async loader so they are correct and work whithout async delay. I don`t know how to make angular wait for my routes definitions and thet start to run the app.

Please, help me. Thanks.

UPD:

@Thierry many thanks for your help again. You are awesome my friend and mentor. One last question (last). Can you tell me how I can define routeConfig into one app file with child subrouting definition? Its mean. I have main level routes into app files

{
  path: '/',
  name: 'Dashboard',
  component: DashboardComponent,
  useAsDefault: true
},
{
  path: '/patients/...',
  name: 'Patients',
  component: PatientsComponent
},

and patient sub routes into patientsComponent (@RouteConfig)

{
  path: '/',      // root is appRoot/patients/...
  name: 'PatientsList', component...},
  {
  "name": "Chart",
  "path": "/chart/:id", component...
},

How to define this route config only into one app.file ? (How to configure route with sub routing in one file)?

Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
Velidan
  • 5,526
  • 10
  • 48
  • 86

4 Answers4

8

An option could be to get your configuration before bootstrapping your application.

var injector = Injector.resolveAndCreate([HTTP_PROVIDERS]);
var http = injector.get(Http);

http.get('routes.json').map(res => res.json())
  .subscribe(data => {
    bootstrap(AppComponent, [
      HTTP_PROVIDERS
      provide('routesConfig', { useValue: data })
    ]);
  });

Then you can have access the routes configuration by dependency injection and in a synchronous way:

@Component({
  (...)
})
export class AppComponent {
  constructor(@Inject('routesConfig') private routesConfig, private router:Router) {
    // Configure here your routes
  }
}

These two questions could help you:

Edit

You can leverage the Observable.forkJoin method to load your route configuration from different requests:

var injector = Injector.resolveAndCreate([HTTP_PROVIDERS]);
var http = injector.get(Http);

Observable.forkJoin([
  http.get('mainRoutes.json'),
  http.get('childRoutes.json')
])
.map(responses => {
  return {
    main: res[0].json(),
    children: res[1].json()
   };
 })
  .subscribe(data => {
    bootstrap(AppComponent, [
      HTTP_PROVIDERS
      provide('routesConfig', { useValue: data })
    ]);
  });

Edit1

I think that you could try something like that:

[
  {
    path: '/patients/...',
    name: 'Patients',
    component: PatientsComponent,
    childRoutes: [
      {
        path: '/',      // root is appRoot/patients/...
        name: 'PatientsList', component...
      },
      (...)
    ]
  }
]

But you need to split the content to get different elements according to the hints you want to handle:

  • one for the root:

    [
      {
        path: '/patients/...',
        name: 'Patients',
        component: PatientsComponent
      }
    ]
    
  • several for children. For example for patients:

    [
      {
        path: '/',      // root is appRoot/patients/...
        name: 'PatientsList', component...
      },
      (...)
    ]
    
Community
  • 1
  • 1
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • Thierry thanks for answer, I will try this right now. But I have one more question about this. Right now I keep my routes config into 2 files and include it into 2 different component (one - main Route for app.main, second - child route, for patient (for example)). It`s possible join it`s route config and bootstrap it only in app.ts file ? – Velidan Apr 05 '16 at 16:02
  • You're welcome! Yes you can leverage the Observable.forkJoin method for this... I updated my answer ( the injection remains the same). – Thierry Templier Apr 05 '16 at 16:11
  • Many thanks to you Thierry. So, when I recieve this data and provide it into main app, should I must to use router.config into app constructor instead of @RouteConfig decorator? because I don`t know how to get config from Injector for @RouteConfig. Sorry, please, for dummy questions. – Velidan Apr 05 '16 at 16:15
  • I updated my first post with question for you @Thierry. Can you look on this, please? – Velidan Apr 05 '16 at 16:56
  • I understand you =) Thanks. You are absolutelly right (My JSON same like your example). But is it possible to set route.config for main app. file (and setup route.config - for patientsList) only in *main app file* (without route configuration in patientListComponenr? (after app bootstrapping, i want to setup route config into app file (for parent - app, ang child - patientsList). Is it real? And how to do this if it`s real (when into route.config we need to pass only ONE router definition for ONE component). I absolutelly stuck with this. – Velidan Apr 05 '16 at 19:28
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/108323/discussion-between-velidan-and-thierry-templier). – Velidan Apr 05 '16 at 19:33
5

In the new router (>= RC.3) https://angular.io/docs/js/latest/api/router/index/Router-class.html#!#resetConfig-anchor resetConfig can be used

router.resetConfig([
 { path: 'team/:id', component: TeamCmp, children: [
   { path: 'simple', component: SimpleCmp },
   { path: 'user/:name', component: UserCmp }
 ] }
]);

See also https://github.com/angular/angular/issues/9472#issuecomment-229230093

  • You can load components asynchronously by providing a SystemJsComponentResolver.
  • Right now, you can load routes asynchronously and imperatively update the configuration using resetConfig.
  • Once AppModules are in master, we will utilize those to implement async loading of subconfigs.

https://github.com/angular/angular/issues/11437#issuecomment-245995186 provides an RC.6 Plunker

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
0

Check this: DynamicalAsyncRouter

https://github.com/Longfld/DynamicalAsyncRouter

Long Field
  • 858
  • 9
  • 16
0

Using Observables/Promises to provide route translations is not a reliable solution, hence the Angular router expects Route[] or Routes, but an HTTP request can only return an Observable/Promise.

The Angular app gets initialized, but the retrieval process of route translations still goes on using Observables/Promises.

As Thierry Templier said, to get your configuration before bootstrapping your application would solve the problem.

Also, check the @ngx-i18n-router/core on github.

Burak Tasci
  • 887
  • 12
  • 18