I have the following configuration for my route:
$routeProvider.when('/', {
controller: 'homeController',
templateUrl: 'app/views/main/home.html'
})
.when('/:section/:tree', {
templateUrl: function($routeParams) { return 'App/Views/'+$routeParams.section+'/'+$routeParams.tree+'.html'; },
controller: function ($routeParams) { return $routeParams.tree + 'Controller'; }
})
.otherwise({
redirectTo: '/'
});
}
The view is loaded correctly but without controller and the controller function is not even called.
Is there any way to solve this issue or determine the controller based on route params.
The controller function is not a function returning the controller name. It's supposed to be the controller itself.
Let's suppose the tree route param can be Foo or Bar, you just need
.when('/:section/Foo', {
templateUrl: function($routeParams) { return 'App/Views/'+$routeParams.section+'/Foo.html'; },
controller: 'FooController'
})
.when('/:section/Bar', {
templateUrl: function($routeParams) { return 'App/Views/'+$routeParams.section+'/Bar.html'; },
controller: 'BarController'
})
This, BTW, will avoid your application to cause an exception is the user enters something other than Foo or Bar in the URL.
If you have many similar routes, just use a loop to define them:
['Foo', 'Bar', 'Baz', 'Brr', ...].forEach(function(tree) {
$routeProvider.when('/:section/' + tree, {
templateUrl: function($routeParams) { return 'App/Views/' + $routeParams.section+'/' + tree + '.html'; },
controller: tree + 'Controller'
});
});
Related
I perform a routing upon a broadcast and I need to pass a parameter from $rootScope.$on to a controller through routing.
$rootScope.$on('unauthorized_access', function (event, args) {
$location.path('/login:' + args.msg);
});
Now, this is working.
$routeProvider
.when('/', {
templateUrl: 'mainApp/landingPage/login.html'
})
.when('/login::msg', {
templateUrl: function(params) {
if (params) {
// The params can be printed in console from here...
console.log(params);
}
return 'mainApp/landingPage/login.html';
},
controller: 'loginController'
})
.otherwise({
redirectTo: '/'
});
Now, so far it seems okay. But I need to pass the params to loginController. I tried,
.when('/login::msg', {
templateUrl: function(params) {
if (params) {
console.log(params);
}
return 'mainApp/landingPage/login.html';
},
controller: 'loginController',
pageParams : params
})
but I think, I am doing it wrong. Please help me. Any helps is appreciated. Thank you.
EDIT : I will add a scenario. I need to pass a message-string to loginController from any screen when the 'token' becomes invalid after a fixed time and user is redirected to login screen. Now, when the user arrives for the first time, there is no message to be shown.
Hence, this is how I pass the message to broadcast
$rootScope.$broadcast('unauthorized_access', param);
Use resolve:
$routeProvider
.when("/news", {
templateUrl: "newsView.html",
controller: "newsController",
resolve: {
message: function(messageService){
return messageService.getMessage();
}
}
});
Then in your controller, you can get the data like below:
app.controller("newsController", function (message) {
$scope.message = message;
});
More on this:
http://odetocode.com/blogs/scott/archive/2014/05/20/using-resolve-in-angularjs-routes.aspx
I am trying to load a get service JSON function in the main state resolve function so I can store the data to a scope variable.
The account JSON information is relevant because all sub pages are essentially dependent on the information.
--
The below code is partially working. The account resolve function is being successfully called and even the $http returns a promise (state === 0 though). The issue is when the account function resolves the state.controller is never being called.
$stateProvider
.state('app',{
url: '/',
views: {
'header': {
templateUrl: '../views/templates/partials/header.html',
},
'content': {
templateUrl: '../views/templates/partials/content.html'
},
'footer': {
templateUrl: '../views/templates/partials/footer.html',
}
},
resolve: {
account: function($timeout, accountFactory){
//Comment
return $http({method: 'GET', url: '/account.json'});
}
},
controller: ['$scope', 'account', function($scope, account){
// You can be sure that promiseObj is ready to use!
$scope.data = account;
console.log('SCOPE!!!!!');
}],
})
.state('app.accessory', {
url: 'accessory',
views: {
'content#': {
templateUrl: '../views/accessory/listing.html',
controller: 'accessoryListingCtrl',
controllerAs: 'vm'
}
}
})
}]);
Your parent state config is not correct. When using multiple named views A controller does not belong to a state but to a view, so you should move your controller statement to the specific view declaration, or all of them if you need it everywhere.
See here: https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views
$stateProvider
.state('report',{
views: {
'filters': {
templateUrl: 'report-filters.html',
controller: function($scope){ ... controller stuff just for filters view ... }
},
'tabledata': {
templateUrl: 'report-table.html',
controller: function($scope){ ... controller stuff just for tabledata view ... }
},
'graph': {
templateUrl: 'report-graph.html',
controller: function($scope){ ... controller stuff just for graph view ... }
},
}
})
I don't know why the controller does not get called. But you can start by making sure that resolve always return data.
resolve: {
account: function($timeout, accountFactory){
//Comment
return $http({method: 'GET', url: '/account.json'})
.$promise.then(
function(data) { return data; },
function(error) { return error; });
}
}
I'm creating states via ui-router, and attaching them to the same controller. (although obviously different instances of that controllers are initialized)
Inside of that controller, I'd like to know the name of the template it was initialized for.
My idea was to somehow pass to that controller properties in the stateProvider (ui-sref doesn't solve opening the browser with a deep link), but from my searches so far it appears it can't be done.
I can't simply check the name of the current state, since I'm working with multiple views.
I'm working with the same controller for multiple states and views, the controller can act accordingly as soon as he can know the name of the template he's attached to.
Here's how I create my states and views:
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
var controller = 'textFile';
var base = 'templates';
var views = ['home', 'about'];
for (var i = 0; i < views.length; i++)
{
var view = views[i];
$stateProvider.state(view, {
url: '/' + view,
views: {
'header': {
templateUrl: base + '/header.html',
controller: controller
},
'page': {
templateUrl: base + '/' + view + '.html',
controller: controller
},
'footer': {
templateUrl: base + '/footer.html',
controller: controller
}
}
});
}
}]);
I need to be able to know in textFile for instance if it's attached to header.html, footer.html, etc...
Why don't you use a resolve, so that you can access the unique data for each controller instance. For example:
$stateProvider.state(view, {
url: '/' + view,
views: {
'header': {
templateUrl: base + '/header.html',
controller: 'textFile',
resolve: {
viewName: function() { return 'header'; }
}
},
'page': {
templateUrl: base + '/' + view + '.html',
controller: 'textFile',
resolve: {
viewName: function() { return 'page'; }
}
},
'footer': {
templateUrl: base + '/footer.html',
controller: 'textFile',
resolve: {
viewName: function() { return 'footer'; }
}
}
}
});
Then you can access the value in your controller:
.controller('textFile', function($scope, viewName){
console.log(viewName);
});
Lets say I have two routes defined, served by the same view and controller, such as
/customers/:cutomerId/edit
/customers/add
in a controller I need to determine in which "mode" is view in. How do I map "edit" and "add" segments of the route so that it appears in $routeParams. Is there a way?
You may user route's resolves to solve it.
For example:
myApp.config(function($routeProvider) {
$routeProvider
.when('/customers/:cutomerId/edit', {
templateUrl: 'myView.html',
controller: 'MyController',
resolve: {
mode: function() {
return 'edit';
}
}
})
.when('/customers/add', {
templateUrl: 'myView.html',
controller: 'MyController',
resolve: {
mode: function() {
return 'add';
}
}
});
myApp.controller('MyController', function($scope, mode){
// Now controller knows it's mode.
});
I am asking a similar question to this question: UI Router conditional ui views?, but my situation is a little more complex and I cannot seem to get the provided answer to work.
Basically, I have a url that can be rendered two very different ways, depending on the type of entity that the url points to.
Here is what I am currently trying
$stateProvider
.state('home', {
url : '/{id}',
resolve: {
entity: function($stateParams, RestService) {
return RestService.getEntity($stateParams.id);
}
},
template: 'Home Template <ui-view></ui-view>',
onEnter: function($state, entity) {
if (entity.Type == 'first') {
$state.transitionTo('home.first');
} else {
$state.transitionTo('home.second');
}
}
})
.state('home.first', {
url: '',
templateUrl: 'first.html',
controller: 'FirstController'
})
.state('home.second', {
url: '',
templateUrl: 'second.html',
controller: 'SecondController'
});
I set up a Resolve to fetch the actual entity from a restful service.
Every thing seems to be working until I actually get to the transitionTo based on the type.
The transition seems to work, except the resolve re-fires and the getEntity fails because the id is null.
I've tried to send the id to the transitionTo calls, but then it still tries to do a second resolve, meaning the entity is fetched from the rest service twice.
What seems to be happening is that in the onEnter handler, the state hasn't actually changed yet, so when the transition happens, it thinks it is transitioning to a whole new state rather than to a child state. This is further evidenced because when I remove the entity. from the state name in the transitionTo, it believes the current state is root, rather than home. This also prevents me from using 'go' instead of transitionTo.
Any ideas?
The templateUrl can be a function as well so you check the type and return a different view and define the controller in the view rather than as part of the state configuration. You cannot inject parameters to templateUrl so you might have to use templateProvider.
$stateProvider.state('home', {
templateProvider: ['$stateParams', 'restService' , function ($stateParams, restService) {
restService.getEntity($stateParams.id).then(function(entity) {
if (entity.Type == 'first') {
return '<div ng-include="first.html"></div>;
} else {
return '<div ng-include="second.html"></div>';
}
});
}]
})
You can also do the following :
$stateProvider
.state('home', {
url : '/{id}',
resolve: {
entity: function($stateParams, RestService) {
return RestService.getEntity($stateParams.id);
}
},
template: 'Home Template <ui-view></ui-view>',
onEnter: function($state, entity) {
if (entity.Type == 'first') {
$timeout(function() {
$state.go('home.first');
}, 0);
} else {
$timeout(function() {
$state.go('home.second');
}, 0);
}
}
})
.state('home.first', {
url: '',
templateUrl: 'first.html',
controller: 'FirstController'
})
.state('home.second', {
url: '',
templateUrl: 'second.html',
controller: 'SecondController'
});
I ended up making the home controller a sibling of first and second, rather than a parent, and then had the controller of home do a $state.go to first or second depending on the results of the resolve.
Use verified code for conditional view in ui-route
$stateProvider.state('dashboard.home', {
url: '/dashboard',
controller: 'MainCtrl',
// templateUrl: $rootScope.active_admin_template,
templateProvider: ['$stateParams', '$templateRequest','$rootScope', function ($stateParams, templateRequest,$rootScope) {
var templateUrl ='';
if ($rootScope.current_user.role == 'MANAGER'){
templateUrl ='views/manager_portal/dashboard.html';
}else{
templateUrl ='views/dashboard/home.html';
}
return templateRequest(templateUrl);
}]
});