From 6e5a56f240d8eb9a713cea598a20e0dbf0c47c57 Mon Sep 17 00:00:00 2001 From: Rafael Fernandez Serra Date: Tue, 17 Dec 2019 17:14:38 +0000 Subject: [PATCH] feat(stateService): add transition option 'supercede' so transition can be ignored if one is pending --- src/state/stateService.ts | 4 ++++ src/transition/interface.ts | 12 ++++++++++++ src/transition/transitionService.ts | 1 + test/stateServiceSpec.ts | 19 +++++++++++++++++++ 4 files changed, 36 insertions(+) diff --git a/src/state/stateService.ts b/src/state/stateService.ts index f29623e2..493dc0a6 100644 --- a/src/state/stateService.ts +++ b/src/state/stateService.ts @@ -338,6 +338,10 @@ export class StateService { if (!ref.valid()) return silentRejection(ref.error()); + if (options.supercede === false && getCurrent()) { + return Rejection.ignored('Another transition is in progress and supercede has been set to false in TransitionOptions for the transition. So the transition was ignored in favour of the existing one in progress.').toPromise(); + } + /** * Special handling for Ignored, Aborted, and Redirected transitions * diff --git a/src/transition/interface.ts b/src/transition/interface.ts index 44dbc097..22e575c8 100644 --- a/src/transition/interface.ts +++ b/src/transition/interface.ts @@ -73,6 +73,18 @@ export interface TransitionOptions { * You can define your own Transition Options inside this property and use them, e.g., from a Transition Hook */ custom?: any; + /** + * This option may be used to cancel the active transition (if one is active) in favour of the this one. + * This is the default behaviour or ui-router. + * + * + * - When `true`, the active transition will be canceled and new transition will begin. + * - when `false`, the transition will be canceled if a transition is already running. This can be useful in cases where + * you only want to navigate to a different state if you are not already navigating somewhere. + * + * @default `true` + */ + supercede?: boolean; /** @internalapi */ reloadState?: StateObject; /** @internalapi diff --git a/src/transition/transitionService.ts b/src/transition/transitionService.ts index 561e3066..8ad2af46 100644 --- a/src/transition/transitionService.ts +++ b/src/transition/transitionService.ts @@ -49,6 +49,7 @@ export let defaultTransOpts: TransitionOptions = { inherit: false, notify: true, reload: false, + supercede: true, custom: {}, current: () => null, source: 'unknown', diff --git a/test/stateServiceSpec.ts b/test/stateServiceSpec.ts index 38f23f12..a194ad76 100644 --- a/test/stateServiceSpec.ts +++ b/test/stateServiceSpec.ts @@ -637,6 +637,25 @@ describe('stateService', function() { done(); }); + describe('when supercede TransitionOption is false', () => { + it('ignores transition if another transition is running', async done => { + $state.defaultErrorHandler(() => null); + await initStateTo(A); + + const activeTransition = $state.transitionTo(B, {}); + const superseded = await $state.transitionTo(C, {}, { supercede: false }).catch(err => err); + + const result: Rejection = await superseded; + expect(result.type).toEqual(RejectType.IGNORED); + + await activeTransition; + + expect($state.current).toBe(B); + + done(); + }); + }); + it('aborts pending transitions (last call wins)', async done => { $state.defaultErrorHandler(() => null); await initStateTo(A);