From df6ee240292317fc8809aa1b9b9bc4ff6650509c Mon Sep 17 00:00:00 2001 From: Chris Thielen Date: Mon, 13 Mar 2017 20:09:49 -0500 Subject: [PATCH] fix(onEnter): Fix typescript typing for onEnter/onRetain/onExit Closes https://github.com/angular-ui/ui-router/issues/3260 --- src/directives/viewDirective.ts | 4 +- src/interface.ts | 100 +++++++++++++++++++++---- src/statebuilders/onEnterExitRetain.ts | 2 +- src/statebuilders/views.ts | 2 +- 4 files changed, 88 insertions(+), 20 deletions(-) diff --git a/src/directives/viewDirective.ts b/src/directives/viewDirective.ts index a2ef1d8a6..17d8a5ac4 100644 --- a/src/directives/viewDirective.ts +++ b/src/directives/viewDirective.ts @@ -10,7 +10,7 @@ import { import { extend, unnestR, filter, tail, isDefined, isFunction, isString, trace, parse, - ActiveUIView, TransitionService, ResolveContext, Transition, PathNode, + ActiveUIView, TransitionService, ResolveContext, Transition, PathNode, StateDeclaration, Param, kebobString, HookRegOptions, ViewService, $QLike, Obj, TypedMap } from "ui-router-core"; import {Ng1ViewConfig} from "../statebuilders/views"; @@ -429,7 +429,7 @@ function registerControllerCallbacks($transitions: TransitionService, controller const paramsUpdated = ($transition$: Transition) => { // Exit early if the $transition$ is the same as the view was created within. // Exit early if the $transition$ will exit the state the view is for. - if ($transition$ === viewCreationTrans || $transition$.exiting().indexOf(viewState) !== -1) return; + if ($transition$ === viewCreationTrans || $transition$.exiting().indexOf(viewState as StateDeclaration) !== -1) return; let toParams = $transition$.params("to") as TypedMap; let fromParams = $transition$.params>("from") as TypedMap; diff --git a/src/interface.ts b/src/interface.ts index 02a4532ba..d2d9ad047 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -10,26 +10,55 @@ import { StateDeclaration, _ViewDeclaration, IInjectable, Transition, HookResult * * State hooks are registered as onEnter/onRetain/onExit in state declarations. * State hooks can additionally be injected with $transition$ and $state$ for - * the current [[Transition]] and [[State]] in the transition. + * the current [[Transition]] and [[StateObject]] in the transition. * * Transition State Hooks are callback functions that hook into the lifecycle events of specific states during a transition. * As a transition runs, it may exit some states, retain (keep) states, and enter states. * As each lifecycle event occurs, the hooks which are registered for the event and that state are called (in priority order). * - * @param injectables list of services to inject into the function - * - * @returns a [[HookResult]] which may alter the transition - * - * @see + * #### See also: * * - [[IHookRegistry.onExit]] * - [[IHookRegistry.onRetain]] * - [[IHookRegistry.onEnter]] + * + * #### Example: + * ```js + * onEnter: function() { console.log('Entering'); } + * ``` + * + * Not minification-safe + * ```js + * onRetain: function($state$) { console.log('Retained ' + $state$.name); } + * ``` + * + * Annotated for minification-safety + * ```js + * onExit: [ '$transition$', '$state', function($transition$, $state) { + * // always redirect to 'foo' state when being exited + * if ($transition$.to().name !== 'foo') { + * return $state.target('foo'); + * } + * } ] + * ``` + * + * @returns an optional [[HookResult]] which may alter the transition */ export interface Ng1StateTransitionHook { (...injectables: any[]) : HookResult } +/** + * @internalapi + * an intermediate interface. + * + * Used to reset [[StateDeclaration]] typings to `any` so the [[Ng1StateDeclaration]] interface can then narrow them */ +export interface _Ng1StateDeclaration extends StateDeclaration { + onExit?: any; + onRetain?: any; + onEnter?: any; +} + /** * The StateDeclaration object is used to define a state or nested state. * It should be registered with the [[StateRegistry]]. @@ -95,7 +124,7 @@ export interface Ng1StateTransitionHook { * } * ``` */ -export interface Ng1StateDeclaration extends StateDeclaration, Ng1ViewDeclaration { +export interface Ng1StateDeclaration extends _Ng1StateDeclaration, Ng1ViewDeclaration { /** * An optional object which defines multiple named views. * @@ -246,7 +275,10 @@ export interface Ng1StateDeclaration extends StateDeclaration, Ng1ViewDeclaratio views?: { [key: string]: Ng1ViewDeclaration; }; /** - * State hook that can be injected with `$transition$` or `$state$` for the current transition. + * A state hook invoked when a state is being entered. + * + * The hook can inject global services. + * It can also inject `$transition$` or `$state$` (from the current transition). * * ### Example: * ```js @@ -257,12 +289,25 @@ export interface Ng1StateDeclaration extends StateDeclaration, Ng1ViewDeclaratio * } * }); * ``` + * + * #### Example:` + * ```js + * $stateProvider.state({ + * name: 'mystate', + * onEnter: [ 'MyService', '$transition$', '$state$', function (MyService, $transition$, $state$) { + * return MyService.doSomething($state$.name, $transition$.params()); + * } ] + * }); + * ``` */ - onEnter?: Ng1StateTransitionHook; + onEnter?: Ng1StateTransitionHook | IInjectable; /** - * State hook that can be injected with `$transition$` or `$state$` for the current transition. - * + * A state hook invoked when a state is being exited. + * + * The hook can inject global services. + * It can also inject `$transition$` or `$state$` (from the current transition). + * * ### Example: * ```js * $stateProvider.state({ @@ -272,13 +317,26 @@ export interface Ng1StateDeclaration extends StateDeclaration, Ng1ViewDeclaratio * } * }); * ``` + * + * #### Example:` + * ```js + * $stateProvider.state({ + * name: 'mystate', + * onExit: [ 'MyService', '$transition$', '$state$', function (MyService, $transition$, $state$) { + * return MyService.doSomething($state$.name, $transition$.params()); + * } ] + * }); + * ``` */ - onExit?: Ng1StateTransitionHook; + onExit?: Ng1StateTransitionHook | IInjectable; /** - * State hook that can be injected with `$transition$` or `$state$` for the current transition. - * - * ### Example: + * A state hook invoked when a state is being retained. + * + * The hook can inject global services. + * It can also inject `$transition$` or `$state$` (from the current transition). + * + * #### Example: * ```js * $stateProvider.state({ * name: 'mystate', @@ -287,8 +345,18 @@ export interface Ng1StateDeclaration extends StateDeclaration, Ng1ViewDeclaratio * } * }); * ``` + * + * #### Example:` + * ```js + * $stateProvider.state({ + * name: 'mystate', + * onRetain: [ 'MyService', '$transition$', '$state$', function (MyService, $transition$, $state$) { + * return MyService.doSomething($state$.name, $transition$.params()); + * } ] + * }); + * ``` */ - onRetain?: Ng1StateTransitionHook; + onRetain?: Ng1StateTransitionHook | IInjectable; /** * Makes all search/query parameters `dynamic` diff --git a/src/statebuilders/onEnterExitRetain.ts b/src/statebuilders/onEnterExitRetain.ts index ace9c869f..461bd05e4 100644 --- a/src/statebuilders/onEnterExitRetain.ts +++ b/src/statebuilders/onEnterExitRetain.ts @@ -9,7 +9,7 @@ import { Ng1StateDeclaration } from '../interface'; * This is a [[StateBuilder.builder]] function for angular1 `onEnter`, `onExit`, * `onRetain` callback hooks on a [[Ng1StateDeclaration]]. * - * When the [[StateBuilder]] builds a [[State]] object from a raw [[StateDeclaration]], this builder + * When the [[StateBuilder]] builds a [[StateObject]] object from a raw [[StateDeclaration]], this builder * ensures that those hooks are injectable for angular-ui-router (ng1). */ export const getStateHookBuilder = (hookName: "onEnter"|"onExit"|"onRetain") => diff --git a/src/statebuilders/views.ts b/src/statebuilders/views.ts index 5074ed2ef..85cc81b15 100644 --- a/src/statebuilders/views.ts +++ b/src/statebuilders/views.ts @@ -23,7 +23,7 @@ const hasAnyKey = (keys, obj) => /** * This is a [[StateBuilder.builder]] function for angular1 `views`. * - * When the [[StateBuilder]] builds a [[State]] object from a raw [[StateDeclaration]], this builder + * When the [[StateBuilder]] builds a [[StateObject]] object from a raw [[StateDeclaration]], this builder * handles the `views` property with logic specific to angular-ui-router (ng1). * * If no `views: {}` property exists on the [[StateDeclaration]], then it creates the `views` object