diff --git a/src/ng/directive/ngView.js b/src/ng/directive/ngView.js index 2fd3a6005d88..bab6d3c3b197 100644 --- a/src/ng/directive/ngView.js +++ b/src/ng/directive/ngView.js @@ -157,7 +157,11 @@ var ngViewDirective = ['$http', '$templateCache', '$route', '$anchorScroll', '$c // $anchorScroll might listen on event... $anchorScroll(); } else { - clearContent(); + if ($route.current && $route.current['$route'] && $route.current['$route'].functionRoute) { + // don't clear content when the route is just a function + } else { + clearContent(); + } } } } diff --git a/src/ng/route.js b/src/ng/route.js index 971caa1ccbdb..92acd9c62e9c 100644 --- a/src/ng/route.js +++ b/src/ng/route.js @@ -32,6 +32,8 @@ function $RouteProvider(){ * * Object properties: * + * - `fn` - `{function()=}` - A function to be called when the route is matched. This cannot be used + * in combination with other properties. * - `controller` – `{(string|function()=}` – Controller fn that should be associated with newly * created scope or the name of a {@link angular.Module#controller registered controller} * if passed as a string. @@ -398,39 +400,44 @@ function $RouteProvider(){ $q.when(next). then(function() { if (next) { - var keys = [], - values = [], - template; - - forEach(next.resolve || {}, function(value, key) { - keys.push(key); - values.push(isString(value) ? $injector.get(value) : $injector.invoke(value)); - }); - if (isDefined(template = next.template)) { - if (isFunction(template)) { - template = template(next.params); - } - } else if (isDefined(template = next.templateUrl)) { - if (isFunction(template)) { - template = template(next.params); + if (next.$route && next.$route.fn && isFunction(next.$route.fn)) { + next.$route.functionRoute = true; + next.$route.fn(next.params); + } else { + var keys = [], + values = [], + template; + + forEach(next.resolve || {}, function(value, key) { + keys.push(key); + values.push(isString(value) ? $injector.get(value) : $injector.invoke(value)); + }); + if (isDefined(template = next.template)) { + if (isFunction(template)) { + template = template(next.params); + } + } else if (isDefined(template = next.templateUrl)) { + if (isFunction(template)) { + template = template(next.params); + } + if (isDefined(template)) { + next.loadedTemplateUrl = template; + template = $http.get(template, {cache: $templateCache}). + then(function(response) { return response.data; }); + } } if (isDefined(template)) { - next.loadedTemplateUrl = template; - template = $http.get(template, {cache: $templateCache}). - then(function(response) { return response.data; }); + keys.push('$template'); + values.push(template); } - } - if (isDefined(template)) { - keys.push('$template'); - values.push(template); - } - return $q.all(values).then(function(values) { - var locals = {}; - forEach(values, function(value, index) { - locals[keys[index]] = value; + return $q.all(values).then(function(values) { + var locals = {}; + forEach(values, function(value, index) { + locals[keys[index]] = value; + }); + return locals; }); - return locals; - }); + } } }). // after route change @@ -465,8 +472,17 @@ function $RouteProvider(){ match.$route = route; } }); + // No route matched; fallback to "otherwise" route - return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}}); + if (match == null) { + var route = routes[null]; + match = route && inherit(route, {params: {}, pathParams:{}}); + if (match) { + match.$route = route; + } + } + + return match; } /** diff --git a/test/ng/directive/ngViewSpec.js b/test/ng/directive/ngViewSpec.js index e90bb3bd89e8..bae17e36e553 100644 --- a/test/ng/directive/ngViewSpec.js +++ b/test/ng/directive/ngViewSpec.js @@ -459,4 +459,23 @@ describe('ngView', function() { expect(div.controller()).toBe($route.current.scope.ctrl); }); }); + + it('should not remove the previous routes content if the current route is a function', function() { + module(function($routeProvider) { + $routeProvider.when('/foo', {template: 'angular is da best'}); + $routeProvider.when('/bar', {fn: function() {}}); + }); + + inject(function($rootScope, $compile, $location, $route) { + expect(element.text()).toEqual(''); + + $location.path('/foo'); + $rootScope.$digest(); + expect(element.text()).toEqual('angular is da best'); + + $location.path('/bar'); + $rootScope.$digest(); + expect(element.text()).toEqual('angular is da best'); + }); + }); }); diff --git a/test/ng/routeSpec.js b/test/ng/routeSpec.js index e8e63b77337c..e330c04b9c73 100644 --- a/test/ng/routeSpec.js +++ b/test/ng/routeSpec.js @@ -793,4 +793,27 @@ describe('$route', function() { }); }); }); + + + describe('route functions', function() { + var routeFunctionSpy = jasmine.createSpy('route function spy'); + + function routeFunction(routePathParams) { + routeFunctionSpy(routePathParams); + } + + beforeEach(module(function($routeProvider) { + $routeProvider.when('/foo/:id', {templateUrl: 'foo.html'}); + $routeProvider.when('/bar/:id/:subId', {fn: routeFunction}); + })); + + it ('should allow using a function as a route', function() { + inject(function($route, $location, $rootScope) { + $location.path('/bar/id3/id4'); + $rootScope.$digest(); + + expect(routeFunctionSpy).toHaveBeenCalledWith({id: 'id3', subId: 'id4'}); + }); + }); + }); });