app.config + stateProvider - angularjs

I am using ui.router to handle my app routing, currently my app is small online a couple routes. As of right now they go into app.config, i'd like to spilt out each route configuration based on feature, for example this feature is a for a "Promotion" SPA, how can I go about doing this so I won't clutter my initial app.config js file?
$stateProvider
.state('promotion', {
controller: 'PromotionsController',
url: '',
views: {
"list": {
controller: 'PromotionsController',
templateUrl: templatesRoot + 'Promotion/promotion-list.html'
},
"editor": { template: "Welcome" }
}
})
.state('promotion-edit',
{
url: '/edit/{id}',
views: {
"list": {
controller: 'PromotionsController',
templateUrl: templatesRoot + 'Promotion/promotion-list.html'
},
"editor": {
controller: ['$scope', '$stateParams', 'promotionService', function ($scope, $stateParams, promotionService) {
$scope.promotion = promotionService.getPromotion($stateParams.id)
$scope.savePromotion = function () {
// save the promotion
promotionService.savePromotion($scope.promotion, function (data, responseHeaders) {
if (!data.Success) {
toaster.pop({
type: 'error',
title: 'Error',
body: data.Message,
showCloseButton: true
});
} else {
toaster.pop({
type: 'success',
title: "Success",
body: "Successfully saved the promotion",
showCloseButton: true
});
}
});
};
}],
templateUrl: templatesRoot + 'Promotion/promotion-edit.html'
}
}
}
)
.state('promotion-create',
{
url: '/create',
views: {
"list": {
controller: 'PromotionsController',
templateUrl: templatesRoot + 'Promotion/promotion-list.html'
},
"editor": {
controller: 'PromotionsController',
templateUrl: templatesRoot + 'Promotion/promotion-create.html'
}
}
}
)

Separate your routes into files. For example:
promotion.js
angular.module('AppName').config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {
$stateProvider.state('promotion', {
controller: 'PromotionsController',
url: '',
views: {
"list": {
controller: 'PromotionsController',
templateUrl: templatesRoot + 'Promotion/promotion-list.html'
},
"editor": { template: "Welcome" }
}
})
}]);
Then in your index.html, reference this file:
<script src="pathToRoutes/promotion.js"></script>
After that you should be good to go.

Just put it in a separate files which contain only config blocks.
For example you can have:
app/scripts/app.js # not router configuration
app/scripts/routes/promotions.js # pomotions configuration
app/scripts/routes/featureN.js # n-th feature
app/scripts/routes/custom-states-provider.js
The last one you will need if you notice a lot of code duplication between the features and you want to make a custom wrapper around the ui router $stateProvider with utility functions. Of course there are other solutions to this problem.

Related

How do I get URL parameters on AngularJS SPA when using stateProvider for routing

For example, on the last state on the below code I want to get the value of "category" URL parameter so that I can use it to retrieve some from the database
var app = angular.module("myApp",["ui.router"]);
app.config(function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise("/");
$stateProvider
.state("main", {
url: "/",
views: {
"slider": {
templateUrl: "slider.html"
},
"departments": {
templateUrl: "departments.html"
},
"brands": {
templateUrl: "brands.html"
}
}
})
.state("cart", {
url: "/cart",
views: {
"cart": {
templateUrl: "../account/cart.php"
}
}
})
.state("department", {
url: "/department/:category",
views: {
"department": {
templateUrl: "department.php"
}
}
});
});
Create a controller, pass stateParams and instantiate the controller within the views of the last state
.state("department", {
url: "/department/:category",
views: {
"department": {
templateUrl: "department.php",
controller: "myController"
}
}
});
});
app.controller('myController', function($stateParams) {
var param = $stateParams.category;
document.getElementById("category").value = param;
});

Implementing a minification-safe resolve function using AngularJS, ui-router and uiBreadcrumbs

I am working on an AngularJS app. I've gotten quite a bit done but am stuck trying to implement a resolve using ui-router and uiBreadcrumbs. So here is the problem, how do I implement a resolve which can work well with magnification, the same way controllers are implemented? I have included sample code below for brevity from uiBreadcrumbs. Look at the last state home.userList.detail.
angular.module('yourModule').config(function($stateProvider) {
$stateProvider
.state('home', {
url: '/',
views: {
'content#': {
templateUrl: ...
}
},
data: {
displayName: 'Home'
}
})
.state('home.usersList', {
url: 'users/',
views: {
'content#': {
templateUrl: ...
}
},
data: {
displayName: 'Users'
}
})
.state('home.userList.detail', {
url: ':id',
views: {
'content#': {
templateUrl: ...
}
},
data: {
displayName: '{{ user.firstName }} {{ user.lastName | uppercase }}'
}
resolve: {
user : function($stateParams, userService) {
return userService.getUser($stateParams.id);
}
}
});
Wrap the function in an array object just like a controller:
resolve: {
user : [
'$stateParams', 'userService',
function($stateParams, userService) {
return userService.getUser($stateParams.id);
}
]
}

UI router - Multiple nested named views in a single state

index.html
--navbar.html
--content.html
--customer.html
--netScore.html
--useExp.html
--useExpNest1.html
--useExpNest2.html
--internalPerformance.html
--leftNavPanel.html
I have this kind of view structure and I want to load them all at once so I'm planning to put this in a single state. I saw this answer but it seems that its only applicable for a simple/double nested views(I have 3 or more nested views). How can I put this in a single state, or is there a better way if not possible?
EDIT
I've come up with this solution and it works somehow.
.state('index', {
url: '/',
views: {
'': {
templateUrl: 'app/modules/bulletin/views/index.view.html',
controller: 'indexController'
},
'navbar#index': {
templateUrl: 'app/modules/bulletin/views/index/navbar.view.html',
controller: 'navbarController'
},
'content#index': {
templateUrl: 'app/modules/bulletin/views/index/content.view.html',
controller: 'contentController'
},
'leftNavPanel#index': {
templateUrl: 'app/modules/bulletin/views/index/leftNavPanel.view.html',
controller: 'contentController'
}
}
})
.state('index.content', {
views: {
'customer#index': {
templateUrl: 'app/modules/bulletin/views/index/content/customer.view.html'
},
'internalPerformance#index': {
templateUrl: 'app/modules/bulletin/views/index/content/internalPerformance.view.html'
}
}
})
.state('index.content.customer', {
views: {
'netScore#index.content': {
templateUrl: 'app/modules/bulletin/views/index/content/customer/netScore.view.html'
},
'useExp#index.content': {
templateUrl: 'app/modules/bulletin/views/index/content/customer/useExp.view.html'
}
}
})
.state('index.content.customer.useExp', {
views: {
'useExpNest1#index.content.customer': {
templateUrl: 'app/modules/bulletin/views/index/content/customer/useExp/useExpNest1.view.html'
},
'useExpNest2#index.content.customer': {
templateUrl: 'app/modules/bulletin/views/index/content/customer/useExp/useExpNest2.view.html'
}
}
})
And then add this code to the indexController(most parent controller)
$state.go('index.content');
$state.go('index.content.customer');
$state.go('index.content.customer.useExp');
But this answer is still wrong because, let's say that netScore.html has some child views, we will create route for it then go to that state, but netScore and useExp states are on the same level so only one of them will be loaded if we use
$state.go('index.content');
$state.go('index.content.customer');
$state.go('index.content.customer.netScore');
$state.go('index.content.customer.useExp');
EDIT 2
Here's a plunker of what I've done so far. The view names are slightly different but you will see clearly the problem there
You can use a combination of named views plus abstract: true property to load child views by default
angular.module('sampleModule', [
'ui.router'
]);
angular.module('sampleModule')
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.when('','/');
$stateProvider
.state('main', {
url: '',
abstract: true,
templateUrl: 'main.view.html'
})
.state('main.load', {
url: '/',
abstract: true,
views:{
'content':{
templateUrl:'content.view.html',
},
'navbar':{
templateUrl:'navbar.view.html',
}
}
})
.state('main.load.customer', {
url: '',
abstract: true,
views:{
'customerPerception':{
templateUrl:'content-customerPerception.view.html'
},
'customerExperience':{
templateUrl:'content-customerExperience.view.html'
}
}
})
.state('main.load.customer.netTrustScore', {
url: '',
abstract: true,
views: {
'netTrustScore': {
templateUrl: 'content-customerPerception-netTrustScore.view.html'
},
'useExperience': {
templateUrl: 'content-customerPerception-useExperience.view.html'
},
'trustStatements': {
templateUrl: 'content-customerPerception-trustStatements.view.html'
}
}
})
.state('main.load.customer.netTrustScore.somethingElse', {
url: '',
views: {
'abc': {
templateUrl: 'content-customerExperience-customerComplaints.view.html'
},
'': {
templateUrl: 'content-customerExperience-networkQualityIndex.view.html'
}
}
})
;
}])
.controller('mainController', ['$scope', '$state', function($scope, $state) {
console.log('mainController initialized!');
}]);
here's a plnkr
https://plnkr.co/edit/BBAeWjnGbTsbO1lMguU9?p=preview
Thanks to the guys from AngularJS group in FB. The problem is I put two sibling views in two different states. UI router cant load two states at the same time. So the solution is to put all same level views in a single subState.
Lets assume we have this kind of structure:
index.html
--navbar.html
--content.html
--customer.html
--netScore.html
--netScoreNest1.html
--netScoreNest2.html
--useExp.html
--useExpNest1.html
--useExpNest2.html
--internalPerformance.html
--leftNavPanel.html
the proper routing for this would be like this
.state('index', {
url: '/',
views: {
'': {
templateUrl: 'index.view.html',
controller: 'mainController'
},
'navbar#main': {
templateUrl: 'index/navbar.view.html'
},
'content#main': {
templateUrl: 'index/content.view.html'
},
'leftNavPanel#main': {
templateUrl: 'index/leftNavPanel.view.html'
}
}
})
.state('index.subLevel', {
views: {
'customer#index': {
templateUrl: 'index/content/customer.view.html'
},
'internalPerformance#index': {
templateUrl: 'index/content/internalPerformance.view.html'
}
// IF LEFTNAVPANEL OR NAVBAR HAVE SUB VIEWS, PUT IT HERE
}
})
.state('index.subLevel.subLevel2', {
views: {
'netScore#index.subLevel': {
templateUrl: 'index/content/customer/netScore.view.html'
},
'useExp#index.subLevel': {
templateUrl: 'index/content/customer/useExp.view.html'
}
// IF INTERNALPERFORMANCE HAVE SUB VIEWS, PUT IT HERE
}
})
.state('index.subLevel.subLevel2.subLevel3', {
views: {
'netScoreNest1#index.subLevel.subLevel2': {
templateUrl: 'index/content/customer/netScore/netScoreNest1.view.html'
},
'netScoreNest2#index.subLevel.subLevel2': {
templateUrl: 'index/content/customer/netScore/netScoreNest2.view.html'
},
'useExpNest1#index.subLevel.subLevel2': {
templateUrl: 'index/content/customer/useExp/useExpNest1.view.html'
},
'useExpNest2#index.subLevel.subLevel2': {
templateUrl: 'index/content/customer/useExp/useExpNest2.view.html'
}
}
})
And then in mainController, load the inner most child state, this will automatically load the views of all its parent(up to topmost parent state 'index')
$state.go('index.subLevel.subLevel2.subLevel3');
And thats it. And also here's a plunker to make it easier to understand. (Views and structure are slightly different from this post different. Too lazy to edit)

ui router - abstract state inside à normal one (3 levels)

i'm trying to get work this combination of sub levels routes.
http://plnkr.co/edit/1nBzppJkB45Ljv5SRW4b?p=preview
i took a sample from ui-route on github and added a parent view (contactg).
$stateProvider
.state('contactg', {
url: '/contactg',
templateUrl: 'contactG.html',
onEnter: function () { console.log("enter contactG"); }
})
.state('contactg.contacts', {
abstract: true,
url: '/contacts',
templateUrl: 'contacts.html',
controller: function ($scope) {
$scope.contacts = [{ id: 0, name: "Alice" }, { id: 1, name: "Bob" }];
},
onEnter: function () {
console.log("enter contacts");
}
})
.state('contactg.contacts.list', {
url: '/list',
// loaded into ui-view of parent's template
templateUrl: 'contacts.list.html',
onEnter: function () {
console.log("enter contacts.list");
}
})
.state('contactg.contacts.detail', {
url: '/:id',
// loaded into ui-view of parent's template
templateUrl: 'contacts.detail.html',
controller: function ($scope, $stateParams) {
$scope.person = $scope.contacts[$stateParams.id];
},
onEnter: function () {
console.log("enter contacts.detail");
}
})
My issues is when i click on an item in contactg.contacts.list, the link generated tends to redirect me to /contacts/:id (detail) instead of /contactg/contacts/:id
is there a way to specify that ?
Thanks
Guillaume.

Angular-ui State - Multiple views not seeing my resolve data

For some reason, my resolvedData is not seeing by controllers when using multiple named views (angular-ui ui-router). Has anyone faced this issue?
$stateProvider
.state('page',{
abstract: true,
templateUrl: ...,
controller: abstractController
})
.state('page.index',
url: '/page',
resolve : {
resolvedData: function(CONSTANTS){ return CONSTANTS.data;}
},
views: {
home: {templateUrl: ...,
controller: function(resolvedData){
....
}
},
list: {templateUrl: ...,
controller: function(resolvedData){
....
}
},
edit: {templateUrl: ...,
controller: function(resolvedData){
....
}
}
}
)
The error it gives me is: Error: [$injector:unpr] Unknown provider: resolvedDataProvider <- resolvedData. It is somehow interesting because it happens only in one of the views but not in the others.
I created small working example, showing that your stuff should work
This would be the CONSTANTS:
.factory('CONSTANTS', function() {
return { data: { name : "some name", number : "some number"} };
})
And the same (just explicitly annotated DI) state def:
// States
$stateProvider
.state('page', {
abstract: true,
template: '<div>'
+ '<div ui-view="home"></div>'
+ '<div ui-view="list"></div></div>',
controller: 'abstractController'
})
.state('page.index', {
url: '/page',
resolve: {
resolvedData: ['CONSTANTS',
function(CONSTANTS) {
return CONSTANTS.data;
}
]
},
views: {
home: {
templateUrl: 'tpl.html',
controller: ['resolvedData','$scope',
function(resolvedData, $scope) {
console.log(resolvedData);
$scope.resolvedData = resolvedData;
}
],
},
list: {
template: '<div>list view</div>'
}
}
})
So, the draft of the resolve used above is working. It is the right way...The resolve function is provided with some service ... and returns its property data.
Check that all here

Resources