I'm creating a CMS system so I want the states to be dynamically created. Since you can't make http requests within the config phase I decided to add my routes in the .run() function as described here:
Now when I display a list of links in my navigation partial using the ui-sref directive the url that is appended has 2 forward slashes instead of one. The controller and everything is called accordingly but I can't seem to get rid of the double slashes. Any ideas?
Here is the relevant code:
app.js
var $stateProviderReference;
angular.module('app', [
'ui.router', // Angular UI Routing
'ngStorage', // Angular Storage (local, cookies, session)
'ngAnimate', // Angular Animation
'angular-loading-bar', // Angular Loading Bar
'restangular', // Restangular
'angular.assets.injector', // Custom assets injector
])
.config(function($stateProvider, $urlRouterProvider, RestangularProvider, $httpProvider, cfpLoadingBarProvider){
// Save a reference of our stateProvider
$stateProviderReference = $stateProvider;
// Irrelevant configuration
// States (routes)
$stateProvider
/*
|
| Frontend
|
*/
.state('frontend', {
url: '/',
views: {
'': {
templateUrl: 'app/views/frontend/templates/default/bootstrap.html',
controller: 'FrontendCtrl'
},
'nav@frontend': {
templateUrl: 'app/views/frontend/templates/default/partials/navigation.html',
controller: 'NavCtrl',
resolve: {
pages: function(PageService){
return PageService.all();
}
}
},
'footer@frontend': {
templateUrl: 'app/views/frontend/templates/default/partials/footer.html',
controller: 'FooterCtrl'
},
'page@frontend': {
templateUrl: 'app/views/frontend/pages/page.html',
controller: 'PageCtrl'
}
}
});
.run(function($rootScope, $location, $state, $stateParams, AuthService, CSRF_TOKEN, PageService){
// Retrieve all the pages
PageService.all().then(function(pages){
// Loop through all the pages
angular.forEach(pages, function(page){
// If this is not the homepage
if( page.routeName !== 'frontend' )
{
// Add a state to our stateProvider
$stateProviderReference.state(page.routeName, {
// Set the desired url
url: page.url,
// Views that we are populating
views: {
// Override the page view partial
'page@frontend': {
templateUrl: 'app/views/frontend/pages/page.html',
controller: 'PageCtrl'
}
}
});
}
});
});
navigation.html partial
<ul class="nav navbar-nav">
<li ng-repeat="page in pages">
<a ng-class="{'active': isActive({{page.routeName}})}" ui-sref="{{ page.routeName }}">{{ page.title }}</a>
</li>
</ul>
Page data being retrieved from the db is formatted like this:
{
id: 1,
routeName 'frontend.home',
title: 'Homepage',
url: '/home',
metaData: {
tags: "some random tags",
desc: "some random description"
},
content: "Html goes here",
deletable: 'yes' // or 'no'
}
So everything seems to work except for the double slashes. When I click on the link generated for the above sample code it will send me to the following url:
http://localhost/CMSv2/public/#//home
instead of
http://localhost/CMSv2/public/#/home
I have tried removing the forward slash from the routeName property and then it does not append the double slashes but the controller can't be reached anymore and everything seems to break.
I'm creating a CMS system so I want the states to be dynamically created. Since you can't make http requests within the config phase I decided to add my routes in the .run() function as described here: http://blog.brunoscopelliti./how-to-defer-route-definition-in-an-angularjs-web-app
Now when I display a list of links in my navigation partial using the ui-sref directive the url that is appended has 2 forward slashes instead of one. The controller and everything is called accordingly but I can't seem to get rid of the double slashes. Any ideas?
Here is the relevant code:
app.js
var $stateProviderReference;
angular.module('app', [
'ui.router', // Angular UI Routing
'ngStorage', // Angular Storage (local, cookies, session)
'ngAnimate', // Angular Animation
'angular-loading-bar', // Angular Loading Bar
'restangular', // Restangular
'angular.assets.injector', // Custom assets injector
])
.config(function($stateProvider, $urlRouterProvider, RestangularProvider, $httpProvider, cfpLoadingBarProvider){
// Save a reference of our stateProvider
$stateProviderReference = $stateProvider;
// Irrelevant configuration
// States (routes)
$stateProvider
/*
|
| Frontend
|
*/
.state('frontend', {
url: '/',
views: {
'': {
templateUrl: 'app/views/frontend/templates/default/bootstrap.html',
controller: 'FrontendCtrl'
},
'nav@frontend': {
templateUrl: 'app/views/frontend/templates/default/partials/navigation.html',
controller: 'NavCtrl',
resolve: {
pages: function(PageService){
return PageService.all();
}
}
},
'footer@frontend': {
templateUrl: 'app/views/frontend/templates/default/partials/footer.html',
controller: 'FooterCtrl'
},
'page@frontend': {
templateUrl: 'app/views/frontend/pages/page.html',
controller: 'PageCtrl'
}
}
});
.run(function($rootScope, $location, $state, $stateParams, AuthService, CSRF_TOKEN, PageService){
// Retrieve all the pages
PageService.all().then(function(pages){
// Loop through all the pages
angular.forEach(pages, function(page){
// If this is not the homepage
if( page.routeName !== 'frontend' )
{
// Add a state to our stateProvider
$stateProviderReference.state(page.routeName, {
// Set the desired url
url: page.url,
// Views that we are populating
views: {
// Override the page view partial
'page@frontend': {
templateUrl: 'app/views/frontend/pages/page.html',
controller: 'PageCtrl'
}
}
});
}
});
});
navigation.html partial
<ul class="nav navbar-nav">
<li ng-repeat="page in pages">
<a ng-class="{'active': isActive({{page.routeName}})}" ui-sref="{{ page.routeName }}">{{ page.title }}</a>
</li>
</ul>
Page data being retrieved from the db is formatted like this:
{
id: 1,
routeName 'frontend.home',
title: 'Homepage',
url: '/home',
metaData: {
tags: "some random tags",
desc: "some random description"
},
content: "Html goes here",
deletable: 'yes' // or 'no'
}
So everything seems to work except for the double slashes. When I click on the link generated for the above sample code it will send me to the following url:
http://localhost/CMSv2/public/#//home
instead of
http://localhost/CMSv2/public/#/home
I have tried removing the forward slash from the routeName property and then it does not append the double slashes but the controller can't be reached anymore and everything seems to break.
Share Improve this question asked Aug 25, 2014 at 20:50 HaskababHaskabab 652 silver badges7 bronze badges2 Answers
Reset to default 5The issue es from the fact, that if there are states parent - child their url is parent.url + child.url:
- parent:
.state('frontend', { url: '/',...
- child:
{ routeName 'frontend.home', url: '/home',..
- result:
'/' + '/home' === '//home'
But again there is a nice solution built into the ui-router
:
- Absolute Routes (^)
small cite:
If you want to have absolute url matching, then you need to prefix your url string with a special symbol '^'.
$stateProvider
.state('contacts', {
url: '/contacts',
...
})
.state('contacts.list', {
url: '^/list',
...
});
SOLUTION: (very easy in this case)
Instead of this url def:
{
id: 1,
routeName 'frontend.home',
title: 'Homepage',
url: '/home',
...
We just will path this url: '^/home',
:
{
id: 1,
routeName 'frontend.home',
title: 'Homepage',
url: '^/home',
...
Since your home-state is derived from the frontend-state, the additional slash is added from the frontend-url. To remove the extra initial slash, set the frontend-state to "abstract" and clear the url like so:
.state('frontend', {
abstract: true,
url: '',
templateUrl: 'yourTemplate.html'
})
This better corresponds to your structure as well, since the frontend-state url is never used.