Dynamic partial arguments in AngularJS routing
How about defining a single route with a paramater ?In angularjs v1.x you can defined as many routes you want with as many params xor query
.config(function($routeProvider, $locationProvider) { $routeProvider .when('/city/:slug', { templateUrl: 'book.html', controller: 'BookController', resolve: { // you can also retrieve some data as a resolved promise inside your route for better performance. }})
appRouteProvider.when('/:city/:slug', {templateUrl : 'dafault.html',controller : 'DefaultController',resolve:{ factory: function($routeParams, $http, $location, sharedParams){ var city = $routeParams.city; var slug = $routeParams.slug; var deferred = $q.defer(); sharedParams.getCurrentPageType($routeParams).then(function(t) { if(t=='list'){ $location.path('/' + city + '/' + slug + '/list'); deferred.resolve(); } else if(t=='single'){ $location.path('/' + city + '/' + slug + '/single'); deferred.resolve(); } else { deferred.reject(); } }); return deferred.promise; }, }});appRouteProvider.when('/:city/:slug/list', { templateUrl: '../../app/templates/list.html', controller: 'ListsController',});appRouteProvider.when('/:city/:slug/single', { templateUrl: '../../app/templates/single.html', controller: 'SingleController',});
You can do it with separate routes. The idea is when user hits the main route it resolves first with the data from the backend. If the condition is met, resolve function will redirect to specific route if not it wont pass
Services in Angular cannot be injected in the configuration phase since they become available only in the run phase of an Angular application.
There is however a trick to load $http
service in the config phase which you can use to load your cities/categories and set up your routes. Meanwhile, since controllers aren't registered up until the run phase, you may use the $controllerProvider
to register your controllers beforehand in the configuration phase:
app.config(function ($routeProvider, $controllerProvider) { $controllerProvider.register('ListController', ListController); $controllerProvider.register('SingleController', SingleController); // wire the $http service var initInjector = angular.injector(['ng']); var $http = initInjector.get('$http'); ...});
You can now call your API to get the cities (or whatever else) and iterate while registering each route:
... // fetch the cities from the server $http.get('/cities') .then(function (response) { var cities = response.data; for(var i = 0; i < cities.length; i++){ $routeProvider // assuming each city object has a `name` property .when('/' + cities[i]['name'] + '/:slug', { templateUrl: getTemplate(cities[i]['name']), controller: getController(cities[i]['name']) }) } }); ...
Note that I'm using the getTemplate
and the getController
methods which return the templateUrl
and the relevant controller name strings respectively using an ordinary switch
expression. You can choose your own approach.
Plunkr Demo
Note:
While a function with the templateUrl
route options property does work with setting up a custom template, but when you use a function alongside the controller
property, Angular will consider it as the constructor for the controller. Therefore, returning the name of the controller in that function won't work.