diff --git a/types/ember__routing/-private/route-info.d.ts b/types/ember__routing/-private/route-info.d.ts new file mode 100644 index 00000000000000..6cc971bd9c5189 --- /dev/null +++ b/types/ember__routing/-private/route-info.d.ts @@ -0,0 +1,49 @@ +// https://api.emberjs.com/ember/3.6/classes/RouteInfo +/** + * A `RouteInfo` is an object that contains metadata about a specific route within a `Transition`. + * It is read-only and internally immutable. + * It is also not observable, because a `Transition` instance is never changed after creation. + */ +export default interface RouteInfo { + /** + * A reference to the childe route's `RouteInfo`. + * This can be used to traverse downward to the leafmost `RouteInfo`. + */ + readonly child: RouteInfo | null; + /** + * The final segment of the fully-qualified name of the route, like "index". + */ + readonly localName: string; + /** + * The dot-separated, fully-qualified name of the route, like "people.index". + */ + readonly name: string; + /** + * The ordered list of the names of the params required for this route. + * It will contain the same strings as `Object.keys(params)`, but here the order is significant. + * This allows users to correctly pass params into routes programmatically. + */ + readonly paramNames: string[]; + /** + * The values of the route's parameters. + * These are the same params that are received as arguments to the route's `model` hook. + * Contains only the parameters valid for this route, if any (params for parent or child routes are not merged). + */ + readonly params: { [key: string]: string | undefined }; + /** + * A reference to the parent route's `RouteInfo`. + * This can be used to traverse upward to the topmost `RouteInfo`. + */ + readonly parent: RouteInfo | null; + /** + * The values of any query params on this route. + */ + readonly queryParams: { [key: string]: string | undefined }; + /** + * Allows you to traverse through the linked list of `RouteInfo`s from the topmost to leafmost. + * Returns the first `RouteInfo` in the linked list for which the callback returns true. + * + * @param callback the callback to execute. + */ + find(callback: (item: RouteInfo) => boolean): RouteInfo | undefined; +} diff --git a/types/ember__routing/-private/transition.d.ts b/types/ember__routing/-private/transition.d.ts index 53d06f80e8e360..027e913aca23c6 100644 --- a/types/ember__routing/-private/transition.d.ts +++ b/types/ember__routing/-private/transition.d.ts @@ -1,4 +1,17 @@ +import RouteInfo from './route-info'; + export default interface Transition { + /** + * This property is a `RouteInfo` object that represents where transition originated from. + * It's important to note that a `RouteInfo` is a linked list and this property is simply the head node of the list. + * In the case of an initial render, `from` will be set to `null`. + */ + readonly from: RouteInfo | null; + /** + * This property is a `RouteInfo` object that represents where the router is transitioning to. + * It's important to note that a `RouteInfo` is a linked list and this property is simply the leafmost route. + */ + readonly to: RouteInfo; /** * Aborts the Transition. Note you can also implicitly abort a transition * by initiating another transition while a previous one is underway. diff --git a/types/ember__routing/router-service.d.ts b/types/ember__routing/router-service.d.ts index decc36af341ce5..07349dc7651f1e 100644 --- a/types/ember__routing/router-service.d.ts +++ b/types/ember__routing/router-service.d.ts @@ -1,3 +1,4 @@ +import RouteInfo from '@ember/routing/-private/route-info'; import Transition from '@ember/routing/-private/transition'; import Service from '@ember/service'; @@ -10,6 +11,12 @@ type RouteModel = object | string | number; */ export default class RouterService extends Service { // + /** + * A `RouteInfo` that represents the current leaf route. + * It is guaranteed to change whenever a route transition happens + * (even when that transition only changes parameters and doesn't change the active route) + */ + readonly currentRoute: RouteInfo; /** * Name of the current route. * This property represent the logical name of the route, @@ -212,4 +219,23 @@ export default class RouterService extends Service { modelsD: RouteModel, options?: { queryParams: object } ): string; + + // https://api.emberjs.com/ember/3.6/classes/RouterService/events/routeDidChange?anchor=routeDidChange + /** + * Register a callback for an event. + * + * The `routeWillChange` event is fired at the beginning of any attempted transition with a `Transition` object as the sole argument. + * This action can be used for aborting, redirecting, or decorating the transition from the currently active routes. + * + * The `routeDidChange` event only fires once a transition has settled. + * This includes aborts and error substates. + * Like the `routeWillChange` event it recieves a `Transition` as the sole argument. + * + * @param name the name of the event + * @param callback the callback to execute + */ + on( + name: 'routeDidChange' | 'routeWillChange', + callback: (transition: Transition) => void + ): RouterService; } diff --git a/types/ember__routing/test/router.ts b/types/ember__routing/test/router.ts index be1c16d8218870..cbba58c65db363 100755 --- a/types/ember__routing/test/router.ts +++ b/types/ember__routing/test/router.ts @@ -1,4 +1,3 @@ -import { assertType } from './lib/assert'; import Router from '@ember/routing/router'; import Service, { inject as service } from '@ember/service'; import EmberObject, { get } from '@ember/object'; @@ -52,5 +51,33 @@ const RouterServiceConsumer = Service.extend({ const model = EmberObject.create(); get(this, 'router') .transitionTo('index', model, { queryParams: { search: 'ember' }}); - } + }, + onAndRouteInfo() { + const router = get(this, 'router'); + router + .on('routeWillChange', transition => { + const to = transition.to; + to.child; // $ExpectType RouteInfo | null + to.localName; // $ExpectType string + to.name; // $ExpectType string + to.paramNames; // $ExpectType string[] + to.params.foo; // $ExpectType string | undefined + to.parent; // $ExpectType RouteInfo | null + to.queryParams.foo; // $ExpectType string | undefined + to.find(info => info.name === 'foo'); // $ExpectType RouteInfo | undefined + }) + .on('routeDidChange', transition => { + const from = transition.from; + if (from) { + from.child; // $ExpectType RouteInfo | null + from.localName; // $ExpectType string + from.name; // $ExpectType string + from.paramNames; // $ExpectType string[] + from.params.foo; // $ExpectType string | undefined + from.parent; // $ExpectType RouteInfo | null + from.queryParams.foo; // $ExpectType string | undefined + from.find(info => info.name === 'foo'); // $ExpectType RouteInfo | undefined + } + }); + }, }); diff --git a/types/ember__routing/tsconfig.json b/types/ember__routing/tsconfig.json index c5bd4345498c1c..e7c16536f6e394 100644 --- a/types/ember__routing/tsconfig.json +++ b/types/ember__routing/tsconfig.json @@ -44,6 +44,7 @@ "router.d.ts", "types.d.ts", "-private/router-dsl.d.ts", + "-private/route-info.d.ts", "-private/transition.d.ts", "test/lib/assert.ts", "test/route.ts",