diff --git a/src/state.js b/src/state.js index 730e719f8..816d254e1 100644 --- a/src/state.js +++ b/src/state.js @@ -820,11 +820,33 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) { * }); * * + * @param {string=|object=} state - A state name or a state object, which is the root of the resolves to be re-resolved. + * @example + *
+ * //assuming app application consists of 3 states: 'contacts', 'contacts.detail', 'contacts.detail.item' + * //and current state is 'contacts.detail.item' + * var app angular.module('app', ['ui.router']); + * + * app.controller('ctrl', function ($scope, $state) { + * $scope.reload = function(){ + * //will reload 'contact.detail' and 'contact.detail.item' states + * $state.reload('contact.detail'); + * } + * }); + *+ * + * `reload()` is just an alias for: + *
+ * $state.transitionTo($state.current, $stateParams, { + * reload: true, inherit: false, notify: true + * }); + *+ * @returns {promise} A promise representing the state of the new transition. See * {@link ui.router.state.$state#methods_go $state.go}. */ - $state.reload = function reload() { - return $state.transitionTo($state.current, $stateParams, { reload: true, inherit: false, notify: true }); + $state.reload = function reload(state) { + return $state.transitionTo($state.current, $stateParams, { reload: state || true, inherit: false, notify: true}); }; /** @@ -928,9 +950,11 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) { * - **`relative`** - {object=}, When transitioning with relative path (e.g '^'), * defines which state to be relative from. * - **`notify`** - {boolean=true}, If `true` will broadcast $stateChangeStart and $stateChangeSuccess events. - * - **`reload`** (v0.2.5) - {boolean=false}, If `true` will force transition even if the state or params + * - **`reload`** (v0.2.5) - {boolean=false|string=|object=}, If `true` will force transition even if the state or params * have not changed, aka a reload of the same state. It differs from reloadOnSearch because you'd * use this when you want to force a reload when *everything* is the same, including search params. + * if String, then will reload the state with the name given in reload, and any children. + * if Object, then a stateObj is expected, will reload the state found in stateObj, and any chhildren. * * @returns {promise} A promise representing the state of the new transition. See * {@link ui.router.state.$state#methods_go $state.go}. @@ -975,6 +999,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) { // Starting from the root of the path, keep all levels that haven't changed var keep = 0, state = toPath[keep], locals = root.locals, toLocals = []; + var skipTriggerReloadCheck = false; if (!options.reload) { while (state && state === fromPath[keep] && state.ownParams.$$equals(toParams, fromParams)) { @@ -982,6 +1007,23 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) { keep++; state = toPath[keep]; } + } else if (isString(options.reload) || isObject(options.reload)) { + if (isObject(options.reload) && !options.reload.name) { + throw new Error('Invalid reload state object'); + } + + var reloadState = options.reload === true ? fromPath[0] : findState(options.reload); + if (options.reload && !reloadState) { + throw new Error("No such reload state '" + (isString(options.reload) ? options.reload : options.reload.name) + "'"); + } + + skipTriggerReloadCheck = true; + + while (state && state === fromPath[keep] && state !== reloadState) { + locals = toLocals[keep] = state.locals; + keep++; + state = toPath[keep]; + } } // If we're going to the same state and all locals are kept, we've got nothing to do. @@ -989,7 +1031,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) { // TODO: We may not want to bump 'transition' if we're called from a location change // that we've initiated ourselves, because we might accidentally abort a legitimate // transition initiated from code? - if (shouldTriggerReload(to, from, locals, options)) { + if (!skipTriggerReloadCheck && shouldTriggerReload(to, from, locals, options)) { if (to.self.reloadOnSearch !== false) $urlRouter.update(); $state.transition = null; return $q.when($state.current); diff --git a/test/stateSpec.js b/test/stateSpec.js index 77c9373c6..d0d5f420b 100644 --- a/test/stateSpec.js +++ b/test/stateSpec.js @@ -113,7 +113,30 @@ describe('state', function () { // State param inheritance tests. param1 is inherited by sub1 & sub2; // param2 should not be transferred (unless explicitly set). .state('root', { url: '^/root?param1' }) - .state('root.sub1', {url: '/1?param2' }); + .state('root.sub1', {url: '/1?param2' }) + .state('logA', { + url: "/logA", + template: "