Skip to content

Commit ecdf464

Browse files
Merge branch 'metamatt-matt-reloadonsearch'
2 parents 22a2b10 + 6ca0d77 commit ecdf464

File tree

2 files changed

+54
-8
lines changed

2 files changed

+54
-8
lines changed

src/state.js

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -954,7 +954,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
954954
* have not changed, aka a reload of the same state. It differs from reloadOnSearch because you'd
955955
* use this when you want to force a reload when *everything* is the same, including search params.
956956
* if String, then will reload the state with the name given in reload, and any children.
957-
* if Object, then a stateObj is expected, will reload the state found in stateObj, and any chhildren.
957+
* if Object, then a stateObj is expected, will reload the state found in stateObj, and any children.
958958
*
959959
* @returns {promise} A promise representing the state of the new transition. See
960960
* {@link ui.router.state.$state#methods_go $state.go}.
@@ -1002,7 +1002,6 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
10021002

10031003
// Starting from the root of the path, keep all levels that haven't changed
10041004
var keep = 0, state = toPath[keep], locals = root.locals, toLocals = [];
1005-
var skipTriggerReloadCheck = false;
10061005

10071006
if (!options.reload) {
10081007
while (state && state === fromPath[keep] && state.ownParams.$$equals(toParams, fromParams)) {
@@ -1020,8 +1019,6 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
10201019
throw new Error("No such reload state '" + (isString(options.reload) ? options.reload : options.reload.name) + "'");
10211020
}
10221021

1023-
skipTriggerReloadCheck = true;
1024-
10251022
while (state && state === fromPath[keep] && state !== reloadState) {
10261023
locals = toLocals[keep] = state.locals;
10271024
keep++;
@@ -1034,8 +1031,10 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
10341031
// TODO: We may not want to bump 'transition' if we're called from a location change
10351032
// that we've initiated ourselves, because we might accidentally abort a legitimate
10361033
// transition initiated from code?
1037-
if (!skipTriggerReloadCheck && shouldTriggerReload(to, from, locals, options)) {
1034+
if (shouldSkipReload(to, toParams, from, fromParams, locals, options)) {
10381035
if (to.self.reloadOnSearch !== false) $urlRouter.update();
1036+
$state.params = toParams;
1037+
copy($state.params, $stateParams);
10391038
$state.transition = null;
10401039
return $q.when($state.current);
10411040
}
@@ -1429,8 +1428,27 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
14291428
return $state;
14301429
}
14311430

1432-
function shouldTriggerReload(to, from, locals, options) {
1433-
if (to === from && ((locals === from.locals && !options.reload) || (to.self.reloadOnSearch === false))) {
1431+
function shouldSkipReload(to, toParams, from, fromParams, locals, options) {
1432+
// Return true if there are no differences in non-search (path/object) params, false if there are differences
1433+
function nonSearchParamsEqual(fromAndToState, fromParams, toParams) {
1434+
// Identify whether all the parameters that differ between `fromParams` and `toParams` were search params.
1435+
function notSearchParam(key) {
1436+
return fromAndToState.params[key].location != "search";
1437+
}
1438+
var nonQueryParamKeys = fromAndToState.params.$$keys().filter(notSearchParam);
1439+
var nonQueryParams = pick.apply(this, [fromAndToState.params].concat(nonQueryParamKeys));
1440+
var nonQueryParamSet = new $$UMFP.ParamSet(nonQueryParams);
1441+
return nonQueryParamSet.$$equals(fromParams, toParams)
1442+
}
1443+
1444+
// If reload was not explicitly requested
1445+
// and we're transitioning to the same state we're already in
1446+
// and the locals didn't change
1447+
// or they changed in a way that doesn't merit reloading
1448+
// (reloadOnParams:false, or reloadOnSearch.false and only search params changed)
1449+
// Then return true.
1450+
if (!options.reload && to === from &&
1451+
(locals === from.locals || (to.self.reloadOnSearch === false && nonSearchParamsEqual(from, fromParams, toParams)))) {
14341452
return true;
14351453
}
14361454
}

test/stateSpec.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ describe('state', function () {
2929
HH = { parent: H },
3030
HHH = {parent: HH, data: {propA: 'overriddenA', propC: 'propC'} },
3131
RS = { url: '^/search?term', reloadOnSearch: false },
32+
RSP = { url: '^/:doReload/search?term', reloadOnSearch: false },
3233
OPT = { url: '/opt/:param', params: { param: "100" } },
3334
OPT2 = { url: '/opt2/:param2/:param3', params: { param3: "300", param4: "400" } },
3435
AppInjectable = {};
@@ -55,6 +56,7 @@ describe('state', function () {
5556
.state('OPT', OPT)
5657
.state('OPT.OPT2', OPT2)
5758
.state('RS', RS)
59+
.state('RSP', RSP)
5860

5961
.state('home', { url: "/" })
6062
.state('home.item', { url: "front/:id" })
@@ -212,7 +214,32 @@ describe('state', function () {
212214
});
213215
$q.flush();
214216
expect($location.search()).toEqual({term: 'hello'});
215-
expect(called).toBeFalsy();
217+
expect(called).toBeFalsy();
218+
}));
219+
220+
it('updates $stateParams when state.reloadOnSearch=false, and only query params changed', inject(function ($state, $stateParams, $q, $location, $rootScope){
221+
initStateTo(RS);
222+
$location.search({term: 'hello'});
223+
var called;
224+
$rootScope.$on('$stateChangeStart', function (ev, to, toParams, from, fromParams) {
225+
called = true
226+
});
227+
$q.flush();
228+
expect($stateParams).toEqual({term: 'hello'});
229+
expect(called).toBeFalsy();
230+
}));
231+
232+
it('does trigger state change for path params even if reloadOnSearch is false', inject(function ($state, $q, $location, $rootScope){
233+
initStateTo(RSP, { doReload: 'foo' });
234+
expect($state.params.doReload).toEqual('foo');
235+
var called;
236+
$rootScope.$on('$stateChangeStart', function (ev, to, toParams, from, fromParams) {
237+
called = true
238+
});
239+
$state.transitionTo(RSP, { doReload: 'bar' });
240+
$q.flush();
241+
expect($state.params.doReload).toEqual('bar');
242+
expect(called).toBeTruthy();
216243
}));
217244

218245
it('ignores non-applicable state parameters', inject(function ($state, $q) {
@@ -940,6 +967,7 @@ describe('state', function () {
940967
'OPT',
941968
'OPT.OPT2',
942969
'RS',
970+
'RSP',
943971
'about',
944972
'about.person',
945973
'about.person.item',

0 commit comments

Comments
 (0)