diff --git a/packages/@ember/-internals/routing/lib/services/router.ts b/packages/@ember/-internals/routing/lib/services/router.ts index 14739d18fb7..c8ca3754e44 100644 --- a/packages/@ember/-internals/routing/lib/services/router.ts +++ b/packages/@ember/-internals/routing/lib/services/router.ts @@ -5,27 +5,12 @@ import { assert } from '@ember/debug'; import { readOnly } from '@ember/object/computed'; import { assign } from '@ember/polyfills'; import Service from '@ember/service'; -import { DEBUG } from '@glimmer/env'; import { consumeTag, tagFor } from '@glimmer/validator'; -import { Transition } from 'router_js'; import EmberRouter, { QueryParam } from '../system/router'; import { extractRouteArgs, resemblesURL, shallowEqual } from '../utils'; const ROUTER = symbol('ROUTER') as string; -let freezeRouteInfo: Function; -if (DEBUG) { - freezeRouteInfo = (transition: Transition) => { - if (transition.from !== null && !Object.isFrozen(transition.from)) { - Object.freeze(transition.from); - } - - if (transition.to !== null && !Object.isFrozen(transition.to)) { - Object.freeze(transition.to); - } - }; -} - function cleanURL(url: string, rootURL: string) { if (rootURL === '/') { return url; @@ -34,6 +19,17 @@ function cleanURL(url: string, rootURL: string) { return url.substr(rootURL.length, url.length); } +function getRouter(owner: Owner): EmberRouter | null { + try { + return owner.lookup('router:main', { instantiate: false }) || null; + } catch (error) { + if (error.message !== 'Could not create factory') { + throw error; + } + return null; + } +} + /** The Router service is the public API that provides access to the router. @@ -72,32 +68,10 @@ export default class RouterService extends Service { return router; } const owner = getOwner(this) as Owner; - router = owner.lookup('router:main') as EmberRouter; - router.setupRouter(); + router = getRouter(owner) as EmberRouter | null; return (this[ROUTER] = router); } - constructor(owner: Owner) { - super(owner); - - const router = owner.lookup('router:main') as EmberRouter; - - router.on('routeWillChange', (transition: Transition) => { - if (DEBUG) { - freezeRouteInfo(transition); - } - this.trigger('routeWillChange', transition); - }); - - router.on('routeDidChange', (transition: Transition) => { - if (DEBUG) { - freezeRouteInfo(transition); - } - - this.trigger('routeDidChange', transition); - }); - } - /** Transition the application into another route. The route may be either a single route or route path: diff --git a/packages/@ember/-internals/routing/lib/system/router.ts b/packages/@ember/-internals/routing/lib/system/router.ts index 1fa016d866a..b019ce2fbf6 100644 --- a/packages/@ember/-internals/routing/lib/system/router.ts +++ b/packages/@ember/-internals/routing/lib/system/router.ts @@ -3,6 +3,7 @@ import { OutletState as GlimmerOutletState, OutletView } from '@ember/-internals import { computed, get, notifyPropertyChange, set } from '@ember/-internals/metal'; import { FactoryClass, getOwner, Owner } from '@ember/-internals/owner'; import { BucketCache } from '@ember/-internals/routing'; +import RouterService from '@ember/-internals/routing/lib/services/router'; import { A as emberA, Evented, Object as EmberObject, typeOf } from '@ember/-internals/runtime'; import Controller from '@ember/controller'; import { assert, deprecate, info } from '@ember/debug'; @@ -23,6 +24,7 @@ import Route, { ROUTER_EVENT_DEPRECATIONS, } from './route'; import RouterState from './router_state'; + /** @module @ember/routing */ @@ -78,6 +80,30 @@ function defaultWillTransition( } } +let freezeRouteInfo: Function; +if (DEBUG) { + freezeRouteInfo = (transition: Transition) => { + if (transition.from !== null && !Object.isFrozen(transition.from)) { + Object.freeze(transition.from); + } + + if (transition.to !== null && !Object.isFrozen(transition.to)) { + Object.freeze(transition.to); + } + }; +} + +function getRouterService(owner: Owner): RouterService | null { + try { + return owner.lookup('service:router', { instantiate: false }) || null; + } catch (error) { + if (error.message !== 'Could not create factory') { + throw error; + } + return null; + } +} + interface RenderOutletState { name: string; outlet: string; @@ -286,12 +312,26 @@ class EmberRouter extends EmberObject { routeWillChange(transition: Transition) { router.trigger('routeWillChange', transition); + const routerService: RouterService | null = getRouterService(owner); + if (routerService) { + if (DEBUG) { + freezeRouteInfo(transition); + } + routerService.trigger('routeWillChange', transition); + } } routeDidChange(transition: Transition) { router.set('currentRoute', transition.to); once(() => { router.trigger('routeDidChange', transition); + const routerService: RouterService | null = getRouterService(owner); + if (routerService) { + if (DEBUG) { + freezeRouteInfo(transition); + } + routerService.trigger('routeDidChange', transition); + } }); } diff --git a/packages/ember/tests/routing/router_service_test/basic_test.js b/packages/ember/tests/routing/router_service_test/basic_test.js index c8407929de9..818b5fbe5a3 100644 --- a/packages/ember/tests/routing/router_service_test/basic_test.js +++ b/packages/ember/tests/routing/router_service_test/basic_test.js @@ -1,6 +1,7 @@ import { Route, NoneLocation } from '@ember/-internals/routing'; import { set } from '@ember/-internals/metal'; import { RouterTestCase, moduleFor } from 'internal-test-helpers'; +import { inject as injectService } from '@ember/service'; moduleFor( 'Router Service - main', @@ -150,5 +151,20 @@ moduleFor( assert.ok(location instanceof NoneLocation); }); } + + ['@test RouterService can be injected into router and accessed on init'](assert) { + assert.expect(1); + + this.router.reopen({ + routerService: injectService('router'), + init() { + this.routerService.one('routeDidChange', () => { + assert.ok(true, 'routeDidChange event listener called'); + }); + }, + }); + + return this.visit('/'); + } } ); diff --git a/packages/ember/tests/routing/router_service_test/non_application_test_test.js b/packages/ember/tests/routing/router_service_test/non_application_test_test.js index ffaf14b3c10..6ae7abe1232 100644 --- a/packages/ember/tests/routing/router_service_test/non_application_test_test.js +++ b/packages/ember/tests/routing/router_service_test/non_application_test_test.js @@ -47,12 +47,27 @@ moduleFor( assert.expect(5); assert.equal(this.routerService.get('currentRouteName'), null); assert.equal(this.routerService.get('currentURL'), null); + assert.equal(this.routerService.get('location'), null); + assert.equal(this.routerService.get('rootURL'), null); + assert.equal(this.routerService.get('currentRoute'), null); + } + + ['@test RouterService properties of router can be accessed with default when router is present']( + assert + ) { + assert.expect(5); + let router = this.owner.lookup('router:main'); + router.setupRouter(); + assert.equal(this.routerService.get('currentRouteName'), null); + assert.equal(this.routerService.get('currentURL'), null); assert.ok(this.routerService.get('location') instanceof NoneLocation); assert.equal(this.routerService.get('rootURL'), '/'); assert.equal(this.routerService.get('currentRoute'), null); } ['@test RouterService#urlFor returns url'](assert) { + let router = this.owner.lookup('router:main'); + router.setupRouter(); assert.equal(this.routerService.urlFor('parent.child'), '/child'); } @@ -60,6 +75,8 @@ moduleFor( assert.expect(2); let componentInstance; + let router = this.owner.lookup('router:main'); + router.setupRouter(); this.addTemplate('parent.index', '{{foo-bar}}'); @@ -90,6 +107,8 @@ moduleFor( } ['@test RouterService#recognize recognize returns routeInfo'](assert) { + let router = this.owner.lookup('router:main'); + router.setupRouter(); let routeInfo = this.routerService.recognize('/dynamic-with-child/123/1?a=b'); assert.ok(routeInfo); let { name, localName, parent, child, params, queryParams, paramNames } = routeInfo;