Skip to content

Instantly share code, notes, and snippets.

@buschtoens
Last active July 23, 2019 03:43
Show Gist options
  • Save buschtoens/de2faacfc8977e39843b7e2cc2f3fd1e to your computer and use it in GitHub Desktop.
Save buschtoens/de2faacfc8977e39843b7e2cc2f3fd1e to your computer and use it in GitHub Desktop.
Engine Router Service
import Ember from 'ember';
import Service from '@ember/service';
import { action, computed } from '@ember/object';
import { getOwner } from '@ember/application';
import { reads } from '@ember/object/computed';
import { assert } from '@ember/debug';
import Evented from '@ember/object/evented';
import CoreObject from '@ember/object/core';
// Import { getEngineParent } from '@ember/engine/lib/engine-parent';
// @HACK: since `getEngineParent` is not exported
function getEngineParent(engine) {
const symbolPrefix = `__ENGINE_PARENT${Ember.GUID_KEY}`;
const symbol = Object.keys(engine).find(k => k.startsWith(symbolPrefix));
if (!symbol) {
return null;
}
return engine[symbol];
}
export default class RouterService extends Service.extend(Evented) {
init() {
super.init();
this.externalRouter.on('routeWillChange', this.onRouteWillChange);
this.externalRouter.on('routeDidChange', this.onRouteDidChange);
}
destroy(): CoreObject {
this.externalRouter.off('routeWillChange', this.onRouteWillChange);
this.externalRouter.off('routeDidChange', this.onRouteDidChange);
return super.destroy();
}
@action
onRouteWillChange(...args: any[]) {
this.trigger('routeWillChange', ...args);
}
@action
onRouteDidChange(...args: any[]) {
this.trigger('routeDidChange', ...args);
}
@computed()
private get engine() {
return getOwner(this);
}
@reads('engine.mountPoint')
private mountPoint!: string;
@reads('engine._externalRoutes')
private externalRoutes!: { [key: string]: string };
@computed('engine')
private get rootApplication() {
let parent = getEngineParent(this.engine);
while (getEngineParent(parent)) {
parent = getEngineParent(parent);
}
return parent;
}
@computed('rootApplication')
private get externalRouter() {
return this.rootApplication.lookup('service:router');
}
@reads('externalRouter.currentURL')
currentURL!: 'string';
@reads('externalRouter.location')
location!: 'auto' | 'hash' | 'history' | 'none';
@reads('externalRouter.rootURL')
rootURL!: string;
@computed('externalRouter.currentRouteName')
get currentRouteName() {
if (this.externalRouter.currentRouteName === this.mountPoint) {
return 'application';
}
return this.externalRouter.currentRouteName.slice(this.mountPoint.length + 1);
}
private getAbsoluteInternalRouteName(internalRouteName: string): string {
// https://github.com/ember-engines/ember-engines/blob/ec4d1ae7a413a7e5d9e57a4e3b2e0f0d19a0afcd/addon/components/link-to-component.js#L52-L57
if (internalRouteName === 'application') {
return this.mountPoint;
}
return `${this.mountPoint}.${internalRouteName}`;
}
private getAbsoluteExternalRouteName(externalRouteName: string): string {
assert(
`External route '${externalRouteName}' is unknown.`,
externalRouteName in this.externalRoutes
);
return this.externalRoutes[externalRouteName];
}
transitionTo(routeName: string, ...params: any[]) {
return this.externalRouter.transitionTo(
this.getAbsoluteInternalRouteName(routeName),
...params
);
}
transitionToExternal(routeName: string, ...params: any[]) {
return this.externalRouter.transitionTo(
this.getAbsoluteExternalRouteName(routeName),
...params
);
}
replaceWith(routeName: string, ...params: any[]) {
return this.externalRouter.replaceWith(
this.getAbsoluteInternalRouteName(routeName),
...params
);
}
replaceWithExternal(routeName: string, ...params: any[]) {
return this.externalRouter.replaceWith(
this.getAbsoluteExternalRouteName(routeName),
...params
);
}
urlFor(routeName: string, ...params: any[]): string {
return this.externalRouter.urlFor(
this.getAbsoluteInternalRouteName(routeName),
...params
);
}
urlForExternal(routeName: string, ...params: any[]): string {
return this.externalRouter.urlFor(
this.getAbsoluteExternalRouteName(routeName),
...params
);
}
isActive(routeName: string, ...params: any[]): string {
return this.externalRouter.isActive(
this.getAbsoluteInternalRouteName(routeName),
...params
);
}
isActiveExternal(routeName: string, ...params: any[]): string {
return this.externalRouter.isActive(
this.getAbsoluteExternalRouteName(routeName),
...params
);
}
}
@villander
Copy link

villander commented Jul 2, 2019

export default Service.extend(Evented, {
  init() {
    this._super(...arguments);

    this.externalRouter.on('routeWillChange', this.onRouteWillChange);
    this.externalRouter.on('routeDidChange', this.onRouteDidChange);
  },

  destroy() {
    this.externalRouter.off('routeWillChange', this.onRouteWillChange);
    this.externalRouter.off('routeDidChange', this.onRouteDidChange);
    return this._super(...arguments);
  },

  onRouteWillChange(...args) {
    this.trigger('routeWillChange', ...args);
  },
  
  onRouteDidChange(...args) {
    this.trigger('routeDidChange', ...args);
  },
....

@buschtoens your solution on JavaScript are returning this error on onRouteDidChange callback

vendor-prefix.js:1 Uncaught (in promise) RangeError: Maximum call stack size exceeded
    at RouterService.trigger (vendor-prefix.js:1)
    at RouterService.onRouteDidChange (engine-router-service.js:68)
    at sendEvent (metal.js:345)
    at RouterService.trigger (evented.js:110)
    at RouterService.onRouteDidChange (engine-router-service.js:68)
    at sendEvent (metal.js:345)
    at RouterService.trigger (evented.js:110)
    at RouterService.onRouteDidChange (engine-router-service.js:68)
    at sendEvent (metal.js:345)
    at RouterService.trigger (evented.js:110)
Promise.then (async)

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