Skip to content

Instantly share code, notes, and snippets.

@tdamir
Last active November 29, 2018 15:55
Show Gist options
  • Save tdamir/34861b86c015e3fb5c0e25d477b11bbb to your computer and use it in GitHub Desktop.
Save tdamir/34861b86c015e3fb5c0e25d477b11bbb to your computer and use it in GitHub Desktop.
Aurelia parent+child route generation
import { autoinject } from 'aurelia-dependency-injection';
import { Router, RouterConfiguration } from 'aurelia-router';
import { CompositionEngine } from 'aurelia-templating';
import { relativeToFile } from 'aurelia-path';
import { Origin } from 'aurelia-metadata';
/**
* Usage:
* app.ts
* async attached(params, routeConfig, navigationInstruction) {
* await this.routeGenerator.configure(this.router);
* }
*
* page.ts
*
* let url = routeGeneratorService.generate([{ route: 'products', params: { id: 1 } }, { route: 'top', params: { top: 100 } } ])
* // url should be 'products/1/top/100'
*
*/
@autoinject()
export class RouteGeneratorService {
private _isConfigured: boolean = false;
private _routers: Router[] = [];
constructor(private compositionEngine: CompositionEngine) {
}
public async configure(router: Router) {
this._routers.push(router);
let childRouters = await this.getChildRouters(router);
this._routers.push(...childRouters);
this._isConfigured = true;
}
private async getChildRouters(router: Router): Promise<Array<Router>> {
let routers: Array<Router> = [];
for (let i = 0; i < router.navigation.length; i++) {
let navModel = router.navigation[i];
if (navModel.config.moduleId) {
const childContainer = router.container.createChild();
let context: any = {
viewModel: relativeToFile(navModel.config.moduleId, Origin.get((<any>router.container).viewModel.constructor).moduleId),
container: router.container,
childContainer: childContainer,
view: (<any>navModel.config).view || (<any>navModel.config).viewStrategy
};
context = await this.compositionEngine.ensureViewModel(context);
if ('configureRouter' in context.viewModel) {
const childRouter = new Router(childContainer, router.history)
const childConfig = new RouterConfiguration()
context.viewModel.configureRouter(childConfig, childRouter);
childConfig.exportToRouter(childRouter);
routers.push(childRouter);
let childRouters = await this.getChildRouters(childRouter);
routers.push(...childRouters);
}
}
}
return routers;
}
public generate(routes: [{ routeName: string, params?: any, options?: any }]): string {
if (!this._isConfigured)
return '';
return routes.map(route => {
return this._generate(route.routeName, route.params, route.options).replace('#', '');
}).join('');
}
private _generate(routeName: string, params?: any, options?: any): string {
if (!this._isConfigured)
return '';
let url: string = '';
for (let i = 0; i < this._routers.length; i++) {
let router = this._routers[i];
if (router.hasRoute(routeName)) {
url = router.generate(routeName, params, options);
break;
}
}
return url;
}
}
@marekpw
Copy link

marekpw commented May 7, 2017

Any ideas why the routes aren't generated before calling the generate method in a child module?

app.ts:

public async attached() {
    console.log('App attached');
    await this.routeGenerator.configure(this.router);
}

showcase.ts:

public attached() {
    console.log('Showcase attached');

    console.log('generating route: ');
    console.log(this.generator.generate([{route: 'showcase'}, {route: 'browse'}]));
}

route-generator.ts:

public async configure(router: Router) {
    this._routers.push(router);
    let childRouters = await this.getChildRouters(router);
    this._routers.push(...childRouters);
    this._isConfigured = true;
    console.log('Configured now');
}

output:

App attached
Showcase attached
generating route:

Configured now

@larvanitis
Copy link

@tdamir The jsdoc should be:

/**
 * Usage: 
 *  app.ts
 *    async activate() {
 *      await this.routeGenerator.configure(this.router);
 *    }
 * 
 *  page.ts
 * 
 *  let url = routeGeneratorService.generate([{ routeName: 'products', params: { id: 1 } }, { routeName: 'top', params: { top: 100 } } ]) 
 *  // url should be 'products/1/top/100'
 * 
 */

@marekpw Better late than never... attached() is not async but activate() is. You can simply put the routeGenerator.configure() inside activate, like mentioned above, and it should work.

@larvanitis
Copy link

larvanitis commented Nov 29, 2018

WARNING: This breaks route lazy loading.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment