Skip to content

Commit 23e2b78

Browse files
fix(Transition): Use { location: replace } when redirecting a transtition in response to a URL sync
This fixes a problem that occurred when the url sync caused a redirection: - URL changes (to `/foo`) - Router synchronizes - Router redirects elsewhere (to `/bar`) - Url is updated Now the browser history has two history entries: - `/foo` - `/bar` --- Now, when the URL is updated, it uses `{ location: replace }` so the browser history only has one entry: - `/bar` Closes angular-ui/ui-router#3187 Closes #15
1 parent 7e0a8af commit 23e2b78

File tree

2 files changed

+51
-5
lines changed

2 files changed

+51
-5
lines changed

src/transition/transition.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,15 @@ export class Transition implements IHookRegistry {
508508
if (++redirects > 20) throw new Error(`Too many consecutive Transition redirects (20+)`);
509509
}
510510

511-
let newOptions = extend({}, this.options(), targetState.options(), { redirectedFrom: this, source: "redirect" });
511+
let redirectOpts: TransitionOptions = { redirectedFrom: this, source: "redirect" };
512+
// If the original transition was caused by URL sync, then use { location: 'replace' }
513+
// on the new transition (unless the target state explicitly specifies location)
514+
if (this.options().source === 'url') {
515+
redirectOpts.location = 'replace';
516+
}
517+
518+
let newOptions = extend({}, this.options(), targetState.options(), redirectOpts);
519+
512520
targetState = new TargetState(targetState.identifier(), targetState.$state(), targetState.params(), newOptions);
513521

514522
let newTransition = this.router.transitionService.create(this._treeChanges.from, targetState);

test/transitionSpec.ts

+42-4
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { PathNode } from "../src/path/node";
22
import {
33
UIRouter, RejectType, Rejection, pluck, services, TransitionService, StateService, Resolvable, Transition
44
} from "../src/index";
5-
import * as vanilla from "../src/vanilla";
65
import { tree2Array, PromiseResult } from "./_testUtils";
6+
import { TestingPlugin } from "./_testingPlugin";
77

88
describe('transition', function () {
99

@@ -30,8 +30,7 @@ describe('transition', function () {
3030

3131
beforeEach(() => {
3232
router = new UIRouter();
33-
router.plugin(vanilla.servicesPlugin);
34-
router.plugin(vanilla.hashLocationPlugin);
33+
router.plugin(TestingPlugin);
3534
$state = router.stateService;
3635
$transitions = router.transitionService;
3736

@@ -60,7 +59,7 @@ describe('transition', function () {
6059
states.forEach(state => router.stateRegistry.register(state));
6160
});
6261

63-
describe('provider', () => {
62+
describe('service', () => {
6463
describe('async event hooks:', () => {
6564
it('$transition$.promise should resolve on success', (done) => {
6665
var result = new PromiseResult();
@@ -674,6 +673,41 @@ describe('transition', function () {
674673
.then(done, done);
675674
}));
676675
});
676+
677+
describe('redirected transition', () => {
678+
let urlRedirect;
679+
beforeEach(() => {
680+
urlRedirect = router.stateRegistry.register({ name: 'urlRedirect', url: '/urlRedirect', redirectTo: 'redirectTarget' });
681+
router.stateRegistry.register({ name: 'redirectTarget', url: '/redirectTarget' });
682+
});
683+
684+
it("should not replace the current url when redirecting a state.go transition", async (done) => {
685+
let spy = spyOn(router.urlService, "url").and.callThrough();
686+
687+
await $state.go("urlRedirect");
688+
expect(router.urlService.path()).toBe("/redirectTarget");
689+
expect(spy).toHaveBeenCalledWith("/redirectTarget", false);
690+
done();
691+
});
692+
693+
it("should replace the current url when redirecting a url sync", (done) => {
694+
let url = spyOn(router.urlService, "url").and.callThrough();
695+
let transitionTo = spyOn(router.stateService, "transitionTo").and.callThrough();
696+
697+
router.transitionService.onSuccess({}, () => {
698+
expect(transitionTo).toHaveBeenCalledWith(urlRedirect, {}, { inherit: true, source: 'url' });
699+
700+
expect(url.calls.count()).toEqual(2);
701+
expect(url.calls.argsFor(0)).toEqual(["/urlRedirect"]);
702+
expect(url.calls.argsFor(1)).toEqual(["/redirectTarget", true]);
703+
704+
done();
705+
});
706+
707+
router.urlService.url('/urlRedirect');
708+
});
709+
710+
});
677711
});
678712

679713
describe('Transition() instance', function() {
@@ -749,4 +783,8 @@ describe('transition', function () {
749783
}));
750784
});
751785
});
786+
});
787+
788+
describe("initial url redirect", () => {
789+
752790
});

0 commit comments

Comments
 (0)