AngularJS - How to use $routeParams in generating the templateUrl?
JavascriptAngularjsJavascript Problem Overview
Our application has 2-level navigating. We want to use AngularJS $routeProvider
to dynamically provide templates to an <ng-view />
. I was thinking of doing something along the lines of this:
angular.module('myApp', []).
config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/:primaryNav/:secondaryNav', {
templateUrl: 'resources/angular/templates/nav/'+<<primaryNavHere>>+'/'+<<secondaryNavHere>>+'.html'
});
}]);
I just don't know how to populate the parts within the <<>>
. I know the primaryNav and secondaryNav get bound to the $routeParams, but how do I access $routeParams here in order to dynamically serve up the template?
Javascript Solutions
Solution 1 - Javascript
This very helpful feature is now available starting at version 1.1.2 of AngularJS. It's considered unstable but I have used it (1.1.3) and it works fine.
Basically you can use a function to generate a templateUrl string. The function is passed the route parameters that you can use to build and return the templateUrl string.
var app = angular.module('app',[]);
app.config(
function($routeProvider) {
$routeProvider.
when('/', {templateUrl:'/home'}).
when('/users/:user_id',
{
controller:UserView,
templateUrl: function(params){ return '/users/view/' + params.user_id; }
}
).
otherwise({redirectTo:'/'});
}
);
Many thanks to https://github.com/lrlopez for the pull request.
Solution 2 - Javascript
I couldn't find a way to inject and use the $routeParams
service (which I would assume would be a better solution) I tried this thinking it might work:
angular.module('myApp', []).
config(function ($routeProvider, $routeParams) {
$routeProvider.when('/:primaryNav/:secondaryNav', {
templateUrl: 'resources/angular/templates/nav/'+$routeParams.primaryNav+'/'+$routeParams.secondaryNav+'.html'
});
});
Which yielded this error: > Unknown provider: $routeParams from myApp
If something like that isn't possible you can change your templateUrl
to point to a partial HTML file that just has ng-include
and then set the URL in your controller using $routeParam
s like this:
angular.module('myApp', []).
config(function ($routeProvider) {
$routeProvider.when('/:primaryNav/:secondaryNav', {
templateUrl: 'resources/angular/templates/nav/urlRouter.html',
controller: 'RouteController'
});
});
function RouteController($scope, $routeParams) {
$scope.templateUrl = 'resources/angular/templates/nav/'+$routeParams.primaryNav+'/'+$routeParams.secondaryNav+'.html';
}
With this as your urlRouter.html
<div ng-include src="templateUrl"></div>
Solution 3 - Javascript
templateUrl can be use as function with returning generated URL. We can manipulate url with passing argument which takes routeParams.
See the example.
.when('/:screenName/list',{
templateUrl: function(params){
return params.screenName +'/listUI'
}
})
Hope this help.
Solution 4 - Javascript
Alright, think I got it...
Little background first: The reason I needed this was to stick Angular on top of Node Express and have Jade process my partials for me.
So here's whatchya gotta do... (drink beer and spend 20+ hours on it first!!!)...
When you set up your module, save the $routeProvider
globally:
// app.js:
var routeProvider
, app = angular.module('Isomorph', ['ngResource']).config(function($routeProvider){
routeProvider = $routeProvider;
$routeProvider
.when('/', {templateUrl: '/login', controller: 'AppCtrl'})
.when('/home', {templateUrl: '/', controller: 'AppCtrl'})
.when('/login', {templateUrl: '/login', controller: 'AppCtrl'})
.when('/SAMPLE', {templateUrl: '/SAMPLE', controller: 'SAMPLECtrl'})
.when('/map', {templateUrl: '/map', controller: 'MapCtrl'})
.when('/chat', {templateUrl: '/chat', controller: 'ChatCtrl'})
.when('/blog', {templateUrl: '/blog', controller: 'BlogCtrl'})
.when('/files', {templateUrl: '/files', controller: 'FilesCtrl'})
.when('/tasks', {templateUrl: '/tasks', controller: 'TasksCtrl'})
.when('/tasks/new', {templateUrl: '/tasks/new', controller: 'NewTaskCtrl'})
.when('/tasks/:id', {templateUrl: '/tasks', controller: 'ViewTaskCtrl'})
.when('/tasks/:id/edit', {templateUrl: '/tasks', controller: 'EditTaskCtrl'})
.when('/tasks/:id/delete', {templateUrl: '/tasks', controller: 'DeleteTaskCtrl'})
.otherwise({redirectTo: '/login'});
});
// ctrls.js
...
app.controller('EditTaskCtrl', function($scope, $routeParams, $location, $http){
var idParam = $routeParams.id;
routeProvider.when('/tasks/:id/edit/', {templateUrl: '/tasks/' + idParam + '/edit'});
$location.path('/tasks/' + idParam + '/edit/');
});
...
That may be more info than what was needed...
-
Basically, you'll wanna store your Module's
$routeProvider
var globally, eg asrouteProvider
so that it can be accessed by your Controllers. -
Then you can just use
routeProvider
and create a NEW route (you can't 'RESET a route' / 'REpromise'; you must create a new one), I just added a slash (/) at the end so that it is as semantic as the first. -
Then (inside your Controller), set the
templateUrl
to the view you want to hit. -
Take out the
controller
property of the.when()
object, lest you get an infinite request loop. -
And finally (still inside the Controller), use
$location.path()
to redirect to the route that was just created.
If you're interested in how to slap an Angular app onto an Express app, you can fork my repo here: https://github.com/cScarlson/isomorph.
And this method also allows for you to keep the AngularJS Bidirectional Data-Bindings in case you want to bind your HTML to your database using WebSockets: otherwise without this method, your Angular data-bindings will just output {{model.param}}
.
If you clone this at this time, you'll need mongoDB on your machine to run it.
Hope this solves this issue!
Cody
Don't drink your bathwater.
Solution 5 - Javascript
I've added support for this in my fork of angular. It allows you to specify
$routeProvider
.when('/:some/:param/:filled/:url', {
templateUrl:'/:some/:param/:filled/template.ng.html'
});
https://github.com/jamie-pate/angular.js/commit/dc9be174af2f6e8d55b798209dfb9235f390b934
not sure this will get picked up as it is kind of against the grain for angular, but it is useful to me
Solution 6 - Javascript
Router:-
...
.when('/enquiry/:page', {
template: '<div ng-include src="templateUrl" onload="onLoad()"></div>',
controller: 'enquiryCtrl'
})
...
Controller:-
...
// template onload event
$scope.onLoad = function() {
console.log('onLoad()');
f_tcalInit(); // or other onload stuff
}
// initialize
$scope.templateUrl = 'ci_index.php/adminctrl/enquiry/'+$routeParams.page;
...
I believe it is a weakness in angularjs that $routeParams is NOT visible inside the router. A tiny enhancement would make a world of difference during implementation.
Solution 7 - Javascript
//module dependent on ngRoute
var app=angular.module("myApp",['ngRoute']);
//spa-Route Config file
app.config(function($routeProvider,$locationProvider){
$locationProvider.hashPrefix('');
$routeProvider
.when('/',{template:'HOME'})
.when('/about/:paramOne/:paramTwo',{template:'ABOUT',controller:'aboutCtrl'})
.otherwise({template:'Not Found'});
}
//aboutUs controller
app.controller('aboutCtrl',function($routeParams){
$scope.paramOnePrint=$routeParams.paramOne;
$scope.paramTwoPrint=$routeParams.paramTwo;
});
in index.html
<a ng-href="#/about/firstParam/secondParam">About</a>
firstParam and secondParam can be anything according to your needs.
Solution 8 - Javascript
I was having a similar issue and used $stateParams
instead of routeParam