diff --git a/src/state.js b/src/state.js index 29d303a52..5901f4141 100644 --- a/src/state.js +++ b/src/state.js @@ -968,6 +968,9 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) { var from = $state.$current, fromParams = $state.params, fromPath = from.path; var evt, toState = findState(to, options.relative); + // Store the hash param for later (since it will be stripped out by various methods) + var hash = toParams['#']; + if (!isDefined(toState)) { var redirect = { to: to, toParams: toParams, options: options }; var redirectResult = handleRedirect(redirect, from.self, fromParams, options); @@ -1117,6 +1120,9 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) { } } + // Re-add the saved hash before we start returning things + if (hash) toParams['#'] = hash; + // Run it again, to catch any transitions in callbacks if ($state.transition !== transition) return TransitionSuperseded; @@ -1342,7 +1348,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) { if (!nav || nav.url === undefined || nav.url === null) { return null; } - return $urlRouter.href(nav.url, filterByKeys(state.params.$$keys(), params || {}), { + return $urlRouter.href(nav.url, filterByKeys(state.params.$$keys().concat('#'), params || {}), { absolute: options.absolute }); }; diff --git a/src/urlRouter.js b/src/urlRouter.js index 2b2293762..7174add31 100644 --- a/src/urlRouter.js +++ b/src/urlRouter.js @@ -351,7 +351,14 @@ function $UrlRouterProvider( $locationProvider, $urlMatcherFactory) { }, push: function(urlMatcher, params, options) { - $location.url(urlMatcher.format(params || {})); + var url = urlMatcher.format(params || {}); + + // Handle the special hash param, if needed + if (url !== null && params && params['#']) { + url += '#' + params['#']; + } + + $location.url(url); lastPushedUrl = options && options.$$avoidResync ? $location.url() : undefined; if (options && options.replace) $location.replace(); }, @@ -395,6 +402,12 @@ function $UrlRouterProvider( $locationProvider, $urlMatcherFactory) { if (!isHtml5 && url !== null) { url = "#" + $locationProvider.hashPrefix() + url; } + + // Handle special hash param, if needed + if (url !== null && params && params['#']) { + url += '#' + params['#']; + } + url = appendBasePath(url, isHtml5, options.absolute); if (!options.absolute || !url) { diff --git a/test/stateSpec.js b/test/stateSpec.js index fa778c3fe..aae3e7524 100644 --- a/test/stateSpec.js +++ b/test/stateSpec.js @@ -488,6 +488,24 @@ describe('state', function () { $state.transitionTo('dynamicController', { type: "Acme" }); $q.flush(); expect(ctrlName).toEqual("AcmeFooController"); + }));+ + + it('updates the location #fragment, if specified', inject(function ($state, $q, $location) { + // html5mode disabled + locationProvider.html5Mode(false); + expect(locationProvider.html5Mode()).toBe(false); + $state.transitionTo('home.item', {id: 'world', '#': 'frag'}); + $q.flush(); + expect($location.url()).toBe('/front/world#frag'); + expect($location.hash()).toBe('frag'); + + // html5mode enabled + locationProvider.html5Mode(true); + expect(locationProvider.html5Mode()).toBe(true); + $state.transitionTo('home.item', {id: 'world', '#': 'frag'}); + $q.flush(); + expect($location.url()).toBe('/front/world#frag'); + expect($location.hash()).toBe('frag'); })); }); diff --git a/test/urlRouterSpec.js b/test/urlRouterSpec.js index f0235ecb2..d25d14105 100644 --- a/test/urlRouterSpec.js +++ b/test/urlRouterSpec.js @@ -173,6 +173,22 @@ describe("UrlRouter", function () { expect($location.url).toHaveBeenCalledWith("/hello/"); })); + it('can push location changes that include a #fragment', inject(function($urlRouter, $location) { + // html5mode disabled + $lp.html5Mode(false); + expect($lp.html5Mode()).toBe(false); + $urlRouter.push(new UrlMatcher('/hello/:name'), {name: 'world', '#': 'frag'}); + expect($location.url()).toBe('/hello/world#frag'); + expect($location.hash()).toBe('frag'); + + // html5mode enabled + $lp.html5Mode(true); + expect($lp.html5Mode()).toBe(true); + $urlRouter.push(new UrlMatcher('/hello/:name'), {name: 'world', '#': 'frag'}); + expect($location.url()).toBe('/hello/world#frag'); + expect($location.hash()).toBe('frag'); + })); + it('can read and sync a copy of location URL', inject(function($urlRouter, $location) { $location.url('/old'); @@ -208,6 +224,18 @@ describe("UrlRouter", function () { expect($urlRouter.href(new UrlMatcher('/hello'))).toBe('#/hello'); })); + + it('should return URLs with #fragments', inject(function($urlRouter) { + // html5mode disabled + $lp.html5Mode(false); + expect($lp.html5Mode()).toBe(false); + expect($urlRouter.href(new UrlMatcher('/hello/:name'), {name: 'world', '#': 'frag'})).toBe('#/hello/world#frag'); + + // html5mode enabled + $lp.html5Mode(true); + expect($lp.html5Mode()).toBe(true); + expect($urlRouter.href(new UrlMatcher('/hello/:name'), {name: 'world', '#': 'frag'})).toBe('/hello/world#frag'); + })); }); });