From 55995fdecfcc9841dfa0f3ec52e4ec1f3cedb02e Mon Sep 17 00:00:00 2001 From: Chris Thielen Date: Wed, 29 Jun 2016 20:02:01 -0500 Subject: [PATCH] feat(rejectFactory): separate transition aborted and transition errored reject types feat(defaultErrorHandler): print stack traces for rejections too. --- src/state/state.ts | 10 +++++----- src/state/stateService.ts | 16 +++++++++++----- src/transition/rejectFactory.ts | 9 ++++++++- src/transition/transitionHook.ts | 2 +- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/state/state.ts b/src/state/state.ts index 8a3cf86f6..5dff96fc9 100644 --- a/src/state/state.ts +++ b/src/state/state.ts @@ -272,18 +272,18 @@ export class StateProvider { } /** - * @ngdoc function - * @name ui.router.state.$stateProvider#onInvalid - * @methodOf ui.router.state.$stateProvider + * Registers an invalid state handler * - * @description - * Registers a function to be injected and invoked when transitionTo has been called with an invalid + * Registers a function to be injected and invoked when [[StateService.transitionTo]] has been called with an invalid * state reference parameter * * This function can be injected with one some special values: * - **`$to$`**: TargetState * - **`$from$`**: TargetState * + * Note: This API is subject to change. + * Replacement of dependency injection support with some alternative is likely. + * * @param {function} callback * The function which will be injected and invoked, when a matching transition is started. * The function may optionally return a {TargetState} or a Promise for a TargetState. If one diff --git a/src/state/stateService.ts b/src/state/stateService.ts index 3b63ccc9e..0048646f9 100644 --- a/src/state/stateService.ts +++ b/src/state/stateService.ts @@ -33,6 +33,7 @@ export class StateService { get current() { return this.router.globals.current; } get $current() { return this.router.globals.$current; } + /** @hidden */ constructor(private router: UIRouter) { let getters = ['current', '$current', 'params', 'transition']; let boundFns = Object.keys(StateService.prototype).filter(key => getters.indexOf(key) === -1); @@ -40,12 +41,13 @@ export class StateService { } /** - * Invokes the onInvalid callbacks, in natural order. Each callback's return value is checked in sequence - * until one of them returns an instance of TargetState. The results of the callbacks are wrapped - * in $q.when(), so the callbacks may return promises. + * Handler for when [[transitionTo]] is called with an invalid state. + * + * Invokes the [[onInvalid]] callbacks, in natural order. + * Each callback's return value is checked in sequence until one of them returns an instance of TargetState. + * The results of the callbacks are wrapped in $q.when(), so the callbacks may return promises. * - * If a callback returns an TargetState, then it is used as arguments to $state.transitionTo() and - * the result returned. + * If a callback returns an TargetState, then it is used as arguments to $state.transitionTo() and the result returned. */ private _handleInvalidTargetState(fromPath: PathNode[], $to$: TargetState) { let globals = this.router.globals; @@ -482,6 +484,10 @@ export class StateService { private _defaultErrorHandler: ((_error) => void) = function $defaultErrorHandler($error$) { if ($error$ instanceof Error && $error$.stack) { console.error($error$.stack); + } else if ($error$ instanceof Rejection) { + console.error($error$); + if ($error$.detail && $error$.detail.stack) + console.error($error$.detail.stack); } else { console.error($error$); } diff --git a/src/transition/rejectFactory.ts b/src/transition/rejectFactory.ts index ecd60b95f..c813088b2 100644 --- a/src/transition/rejectFactory.ts +++ b/src/transition/rejectFactory.ts @@ -4,7 +4,7 @@ import {extend, silentRejection} from "../common/common"; import {stringify} from "../common/strings"; export enum RejectType { - SUPERSEDED = 2, ABORTED = 3, INVALID = 4, IGNORED = 5 + SUPERSEDED = 2, ABORTED = 3, INVALID = 4, IGNORED = 5, ERROR = 6 } export class Rejection { @@ -67,4 +67,11 @@ export class Rejection { let message = "The transition has been aborted."; return new Rejection(RejectType.ABORTED, message, detail); } + + /** Returns a TransitionRejection due to aborted transition */ + static errored(detail?: any) { + // TODO think about how to encapsulate an Error() object + let message = "The transition errored."; + return new Rejection(RejectType.ERROR, message, detail); + } } diff --git a/src/transition/transitionHook.ts b/src/transition/transitionHook.ts index dde6bcab5..d57433f2b 100644 --- a/src/transition/transitionHook.ts +++ b/src/transition/transitionHook.ts @@ -94,7 +94,7 @@ export class TransitionHook { results.push(hooks[i].invokeHook()); } catch (exception) { if (!swallowExceptions) { - return Rejection.aborted(exception).toPromise(); + return Rejection.errored(exception).toPromise(); } console.error("Swallowed exception during synchronous hook handler: " + exception); // TODO: What to do here?