Reputation: 58821
I have an Angular app with a router and a bunch of controllers, organized like
articleApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/articles', {
templateUrl: 'templates/articles/index.html'
}).
when('/articles/:articleId', {
templateUrl: 'templates/articles/article.html'
}).
otherwise({
redirectTo: '/articles'
});
}]);
The controllers are given in the templates, e.g.,
<div ng-controller="ArticleCtrl">
<!-- [...] -->
</div>
Now, I would like to set <head>
data like page title, meta
data etc. depending on the route and the contents of the page. The data is obviously in the controllers, so that's where I'm setting the <head>
data now.
Unfortunately, this is becoming quite a mess: A controller here, a controller there, perhaps active in the same view, this one sets the page title, that one sets the page title... A debugging labyrinth.
Ideally, I would like to set meta data in one place only, and the $routeProvider
above seems ideal to me. Unfortunately, though, we dont't have access to the data of the controllers there. Or do we?
Is it possible to access controller data from the $routeProvider
?
Upvotes: 1
Views: 680
Reputation: 28339
I think you are tackling the problem the wrong way. If this data is needed above the scope of the controller, it should be resolved before the instantiation of the controller. You would then inject this data in the controller the same way you inject any component.
See in particular the documentation for the resolve
property on $routeProvider
.
Here is an example:
$routeProvider
.when('/phone/:phoneId', {
controller: 'PhoneDetailController',
templateUrl: 'phone.detail.html',
resolve: {
routeMetadata: function () {
return {
title: 'Phone product page',
keywords: ['phone', 'mobile', 'cellular']
}
}
}
});
In the controller you just have to inject routeMetadata
:
app.controller('PhoneDetailController', function (..., routeMetadata, ...) {
// ...
}
Besides the resolve
property which is useful in particular if you need to fetch data from an api, you could also use a trick: define the data at the top level of the route definition:
$routeProvider
.when('/phone/:phoneId', {
controller: 'PhoneDetailController',
templateUrl: 'phone.detail.html',
routeMetadata: {
title: 'Phone product page',
keywords: ['phone', 'mobile', 'cellular']
}
});
This data is then accessible in $route.current
. Although I write about this, I would rather go with the resolve
property. The latter is more a workaround, as the difference between properties defined by the module ngRoute
and custom properties is not obvious.
Upvotes: 2
Reputation: 2646
Define a variable in the title tag like
<title>{{ PageSettings.title() }}</title>
Then add a service for it
myModule.factory('PageSettings', function() {
var title = 'default';
return {
title: function() { return title; },
setTitle: function(newTitle) { title = newTitle }
};
});
In your route config, add title
articleApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/articles', {
templateUrl: 'templates/articles/index.html',
title: 'Articles'
}).
when('/articles/:articleId', {
templateUrl: 'templates/articles/article.html',
title: 'Article'
}).
otherwise({
redirectTo: '/articles'
});
}]);
Then you can write your controller like this
function MainCtrl($scope, $route, PageSettings) {
PageSettings.setTitle($route.current.title);
}
Upvotes: 0
Reputation: 22763
If you have to use more information for page like
Then I will suggest to use angularjs-viewhead
If only one or two info then you can set them in routing and at the time of changing the route you can set that.
See how I achieved it by using ui-router
.state('permission', {
title: 'Permission',
url: '/permission',
templateUrl: 'app/views/permission.html',
controller: 'permissionCtrl',
data: {
Roles: [Constants.Roles.admin, Constants.Roles.analyst]
}
})
.state('products', {
title: 'products Page',
url: '/products',
templateUrl: 'app/views/products.html'
});
An on changing the route
app.run(['$rootScope', '$state', function ($rootScope, $state) {
$rootScope.$on('$stateChangeStart', function (event, next) {
// Page Title
$rootScope.title = next.title;
});
}]);
In Html
<title ng-bind="title"></title>
Upvotes: 0