Inner page state cant resolve service - javascript

I am facing very strange issue, while home page can resolve service data, the exactly the same thing is failed for inner page, here is my route code:
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'app/layout/home/home.html',
controller: 'HomeController',
controllerAs: 'vm',
resolve: {
pressData: function (HomeService) {
return HomeService.pressService().query().$promise;
},
countryData: function (countryservice) {
return countryservice.countryServiceData().query().$promise;
}
}
})
.state('create', {
url: '/event/create',
templateUrl: 'app/layout/create-event/create-event.html',
controller: 'CreateEventController',
controllerAs: 'vm',
resolve: {
countryData: function (countryservice) {
return countryservice.countryServiceData().query().$promise;
}
}
});
So countryData is successfully resolved for home state, while is not for create route.
EDIT.
Here is my factory:
angular
.module('GutenChefApp')
.factory('countryservice', countryservice);
countryservice.$inject = ['$resource'];
function countryservice($resource) {
var service = {
countryServiceData: getCountryService
};
return service;
function getCountryService() {
return $resource('app/data/countries.json');
}
}

Related

Unable to load child states in angular

I am facing a very peculiar problem in angular1 and it might need a lot context to understand for someone to answer. I have been working on angular for around 4 weeks now but a very strange problem entangles me.
I have a left vertical menu on a page and a click on it loads the content on right side of the page.
On each click I initiate a state. In this case
$state.go("contrat-synthese", {
id: offer.refEboard
}, {
reload: true
});
The above peice of a code is inside a function which works on the click.
The state "contrat-synthese" is shown below
angular.module('engcApp').config(['$stateProvider', function($stateProvider) {
var lotSelectionState = "synthese-lot";
$stateProvider.state('contrat-synthese', {
parent: 'contrat-lots-resume',
url: '/synthese',
views: {
'content#contrat-lots-resume': {
templateUrl: 'app/entities/views/synthese/synthese.html',
},
'synthese-detail#contrat-synthese': {
templateUrl: 'app/entities/views/synthese/synthese-details.html',
controller: 'ContratSyntheseDetailsController',
controllerAs: 'vm'
},
'synthese-lots-navigation#contrat-synthese': {
templateUrl: 'app/entities/views/common/contrat-lots-navigation.html',
controller: 'ContratLotsNavigationController',
controllerAs: 'vm',
resolve: {
afficherLotComplet: function() {
return false;
},
afficherAnneeComplet: function() {
return false;
},
afficherSelectionAnnee: function() {
return true;
},
afficherLots: function() {
return true;
},
stateNameToUse: function() {
return lotSelectionState;
}
}
},
'synthese-services#contrat-synthese': {
templateUrl: 'app/entities/views/synthese/synthese-services.html',
controller: 'ContratSyntheseServicesController',
controllerAs: 'vm'
}
}
}).state(lotSelectionState, {
parent: "contrat-synthese",
params: {
lots: null
},
views: {
'synthese-composition-lot#contrat-synthese': {
templateUrl: 'app/entities/views/synthese/synthese-composition.html',
controller: 'ContratSyntheseCompositionController',
controllerAs: 'vm'
},
'synthese-volumes-lot#contrat-synthese': {
templateUrl: 'app/entities/views/synthese/synthese-volumes.html',
controller: 'ContratSyntheseVolumesController',
controllerAs: 'vm'
},
'synthese-modules-lot#contrat-synthese': {
templateUrl: 'app/entities/views/synthese/synthese-modules.html',
controller: 'ContratSyntheseModulesController',
controllerAs: 'vm'
},
'synthese-formules-lot#contrat-synthese': {
templateUrl: 'app/entities/views/synthese/synthese-formules.html',
controller: 'ContratSyntheseFormulesController',
controllerAs: 'vm'
},
}
});
}]);
But when I call the state go on page load it is not able to load the lotSelectionState in the synthese state above.
I just don't understand why it is not able to load the states when I call it from outside.
Also child states are not loaded when I click on the link again on the left banner.
Solution I tried for the second case, I tried the following approach:
state.go("contrat-synthese", {
id: offer.refEboard
}, {
reload: true
});
However why am I not able to load the child state? I am so confused :(
Can provide and explain more if needed.

A parameter of ui-router in controller and resolve

I have configured the following ui-router.
app.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('global.editor', {
url: '/posts/editor/{id}',
templateUrl: '/htmls/editor.html',
controller: 'EditorCtrl',
resolve: {
post: ['$stateParams', 'codeService', function ($stateParams, codeService) {
return codeService.getPost($stateParams.id)
}]
}
}
.state('global.new', {
url: '/new',
templateUrl: '/htmls/editor.html',
controller: 'EditorCtrl'
})
.state('global.newTRUE', {
url: '/newTRUE',
templateUrl: '/htmls/editor.html',
controller: 'EditorCtrl'
})
.state('global.editor.panels', {
controller: 'PanelsCtrl',
params: { layout: 'horizontal' },
templateUrl: function (params) { return "/htmls/" + params.layout + '.html' }
}
}])
app.controller('EditorCtrl', ['$scope', '$state', function ($scope, $state) {
$scope.layout = "horizontal";
$scope.$watch('layout', function () {
$state.go('global.editor.panels', { layout: $scope.layout });
});
}]);
As a result, https://localhost:3000/#/new in a browser leads to (the state global.editor, then to) the state global.editor.panels.
Now, I want to add a parameter connected:
I don't want it to be shown in the url
https://localhost:3000/#/new in a browser makes connected to be false, and https://localhost:3000/#/newTRUE in a browser makes connected to be true
connected can be past into the controller EditorCtrl and PanelsCtrl
connected can be available in the resolve of global.editor; ideally, we could resolve different objects according to the value of connected.
Does anyone know how to accomplish this?
You can add resolve for new and newTRUE:
.state('global.new', {
url: '/new',
templateUrl: '/htmls/editor.html',
resolve: {
isConnected: function() {
return false;
}
},
controller: 'EditorCtrl'
})
.state('global.newTRUE', {
url: '/newTRUE',
templateUrl: '/htmls/editor.html',
resolve: {
isConnected: function() {
return true;
}
},
controller: 'EditorCtrl'
})
And in EditorCtrl (or PanelsCtrl) you can use it like:
app.controller('EditorCtrl', ['$scope', '$state', 'isConnected', function($scope, $state, isConnected) {
console.log("connected : " + isConnected); // you can save this value in Service and use it later.
...
}]);
You can use classic approach - in resolve
Or you can use hidden parameters from angular ui router.
Define params : {isConnected' : null} in your parent global state.
In:
global.newTRUE - set value in $state config
global.new - set value in $state config
global.editor.panels - set parameters in transition/go or ui-sref
definition is like this:
$stateProvider
.state('global.newTRUE', {
url : '/:newTRUE',
params : {
'isConnected' : false
}
});
}
and in controller you get in from $stateParams.
Problem with this approach is hidden parameters are loses in refresh page, except if is set default value
You can surely use the params of UI-Router states' config to not show it in URL and achieve all mentioned points.
Also, as per #2, you need connected to be false for /new and true for /newTRUE. We can do so by passing true or false as default value for those states. Something like this:
$stateProvider
.state('global.editor', {
url: '/posts/editor/{id}',
templateUrl: '/htmls/editor.html',
params: { connected: null },
controller: 'EditorCtrl',
resolve: {
post: ['$stateParams', 'codeService', function ($stateParams, codeService) {
return codeService.getPost($stateParams.id)
}]
}
}
.state('global.new', {
url: '/new',
templateUrl: '/htmls/editor.html',
params: { connected: false }, // default false for /new
controller: 'EditorCtrl'
})
.state('global.newTRUE', {
url: '/newTRUE',
templateUrl: '/htmls/editor.html',
params: { connected: true }, // default true for /newTRUE
controller: 'EditorCtrl'
})
.state('global.editor.panels', {
controller: 'PanelsCtrl',
params: { layout: 'horizontal', connected: null },
templateUrl: function (params) { return "/htmls/" + params.layout + '.html' }
}
For #3, In order to access connected in your controllers (EditorCtrl and PanelsCtrl) you can inject $stateParams to controller and use $stateParams.connected to get it.
For #4, (This is more or less similar to achieveing #3)
Just like you get $stateParams.id, you can have $stateParams.connected as well, which you can use to resolve different objects according to the value of connected. Something like this:
.state('global.editor', {
url: '/posts/editor/{id}',
templateUrl: '/htmls/editor.html',
params: { connected: null },
controller: 'EditorCtrl',
resolve: {
post: ['$stateParams', 'codeService', function ($stateParams, codeService) {
return $stateParams.connected ?
codeService.getPost($stateParams.id) :
codeService.getSomethingElse($stateParams.id)
}]
}
}
But, for that to work, make sure that you are passing connected as params when you visit global.editor state (using $state.go or ui-sref)
Hope this helps!

Angular UI router 0.2.15, browser back/forward button not working

I used angular v1.4.7 with UI router 0.2.15, I used $state.go and
ui-sref in case when from html to go to another state. I am unable to
go back. I checked on browser back/forward button but i haven't seen any history got pushed in. So as soon i click on back button it sends me to the empty tab.
'use strict';
/**
* Config for the router
*/
angular.module('app').run(
['$rootScope', '$state', '$stateParams',
function($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
}
]).config(
['$stateProvider', '$urlRouterProvider', 'JQ_CONFIG', 'MODULE_CONFIG',
function($stateProvider, $urlRouterProvider, JQ_CONFIG, MODULE_CONFIG) {
var layout = "tpl/app.html";
$stateProvider.state('app', {
abstract: true,
url: '/app',
templateUrl: layout,
data: {
permissions: {
exept: ['anonymous'],
redirectTo: 'access.signin'
}
},
resolve: load(['toastr', 'js/controllers/modal.js'])
}).state('app.dashboard', {
url: '/dashboard/:tagName',
templateUrl: 'tpl/app_dashboard_v1.html',
controller: 'DashboardController',
data: {
permissions: {
only: ['USER']
}
},
resolve: load(['toastr', 'js/controllers/dashboard.js'])
}).state('app.chat', {
url: '/chat',
templateUrl: 'tpl/chat.html',
controller: 'chatCtrl',
data: {
permissions: {
only: ['USER']
}
},
resolve: load(['toastr', 'js/controllers/chatCtrl.js'])
}).state('app.accounts', {
url: '/accounts/:accountId/:tagName',
templateUrl: 'tpl/group_dash.html',
controller: 'GroupDashController',
data: {
permissions: {
only: ['USER']
}
},
resolve: load(['toastr', 'js/controllers/group_dashboard.js'])
}).state('app.profile', {
url: '/profile/:accountId',
templateUrl: 'tpl/user_profile.html',
data: {
title: 'Profile'
},
controller: 'UserProfileController',
controllerAs: 'vm',
resolve: load(['toastr', 'js/controllers/profile.js'])
}).state('app.feedback', {
url: '/feedback',
templateUrl: 'tpl/feedback.html',
controller: 'feedbackController',
controllerAs: 'vm',
data: {
permissions: {
only: ['USER']
}
},
resolve: load(['toastr', 'js/controllers/feedback.js'])
}).state('access', {
url: '/access',
template: '<div ui-view class="fade-in-right-big smooth"></div>'
}).state('access.signin', {
url: '/signin',
templateUrl: 'tpl/page_signin.html',
resolve: load(['js/controllers/signin.js'])
}).state('access.signout', {
url: '/signout',
templateUrl: 'tpl/page_signout.html',
controller: "SignoutController",
controllerAs: "vm",
data: {
permissions: {
only: ['USER']
}
},
resolve: load(['js/controllers/signout.js'])
}).state('access.signup', {
url: '/signup',
controller: "SignUpController",
controllerAs: "vm",
templateUrl: 'tpl/page_signup.html',
resolve: load(['toastr', 'js/controllers/signup.js'])
}).state('access.forgotpwd', {
url: '/forgotpwd',
controller: "ForgotPassController",
templateUrl: 'tpl/page_forgotpwd.html',
resolve: load(['js/controllers/forgotpwd.js'])
}).state('access.404', {
url: '/404',
templateUrl: 'tpl/page_404.html'
});
$urlRouterProvider.otherwise(function($injector) {
var $state = $injector.get("$state");
$state.go('app.dashboard');
});
function load(srcs, callback) {
return {
deps: ['$ocLazyLoad', '$q',
function($ocLazyLoad, $q) {
var deferred = $q.defer();
var promise = false;
srcs = angular.isArray(srcs) ? srcs : srcs.split(/\s+/);
if (!promise) {
promise = deferred.promise;
}
angular.forEach(srcs, function(src) {
promise = promise.then(function() {
if (JQ_CONFIG[src]) {
return $ocLazyLoad.load(JQ_CONFIG[src]);
}
angular.forEach(MODULE_CONFIG, function(module) {
if (module.name == src) {
name = module.name;
} else {
name = src;
}
});
return $ocLazyLoad.load(name);
});
});
deferred.resolve();
return callback ? promise.then(function() {
return callback();
}) : promise;
}
]
}
}
}
]);

How to unit test onEnter and resolve of ui-router state

I'm trying to test an Angular UI Bootstrap modal that is being called from the onEnter of the following state:
.state("profile.index.edit.services", {
url: "/edit/services/:serviceCode",
parent:"profile.index",
onEnter: ['$stateParams', '$state', '$modal',function($stateParams, $state, $modal) {
$modal.open({
templateUrl: 'profile/edit-services-modal.html',
controller: 'ProfileEditServicesController',
resolve: {
profileData: function(CacheService){
return CacheService.getItem(CacheService.Items.Profile.loadedProfile);
},
allServicesList: function(ProfileService){
return ProfileService.getAllServicesList($stateParams.serviceCode,$stateParams.orgId);
},
serviceCode: function() {
return $stateParams.serviceCode;
}
}
}).result.then(function(result) {
if (result) {
return $state.transitionTo("profile.index", { orgId: $stateParams.orgId });
}
else { // cancel
return $state.transitionTo("profile.index", { orgId: $stateParams.orgId }); // don't reload
}
}, function () {
// executes on close/cancel/ESC
return $state.transitionTo("profile.index", { orgId: $stateParams.orgId });
});
}]
})
I've been banging my ahead against this trying many different things to set the test up, but can't seem to figure it out. Any plunkers or suggestions are greatly appreciated!!!!
By the way, the state above is a descendant of these states, which I've been able to write tests for that pass:
.state('profile.index', {
url: '/:orgId',
views: {
'profile-index#profile': {
templateUrl: 'profile/view-profile.html',
controller: 'ProfileController'
},
'header#': {
templateUrl: 'common/layout/header.html',
controller: 'HeaderController'
},
'footer#':{
templateUrl: 'common/layout/footer.html',
controller: 'FooterController'
}
},
resolve: {
profileData: function(ProfileService, $stateParams){
return ProfileService.getProfile($stateParams.orgId, true);
}
}
})
.state('profile.index.edit', {
url: '',
abstract: true
})
did you ever figure this out? you should have passed a named controller, that way you could test that controller (since it would just be a function) directly instead of relying on onEnter being fired.

angular-ui-router nested views

I have an app with 3 views (A,B,C) and 2 states(1,2)
html
<div ui-view="A"></div>
<div ui-view="B"></div>
<div ui-view="C"></div>
The two states are called list and create. In both states the template and controller of view A + B stay the same but view c should change templates and controllers. I can get view c's content to change but it refreshes view A and view B as it does ie things that are in their controllers run again.
What is the correct way to organise the router to prevent this?
js so far
$urlRouterProvider.otherwise("/basestate/list");
$stateProvider
.state('baseState', function() {
url:"/basestate",
templateUrl: "basestate.html",
controller: 'BaseStateCtrl'
})
.state('baseState.list', function() {
url: "/list",
views: {
"viewA#baseState": {
templateUrl: "viewA.html"
controller: "ViewACtrl"
},
"viewB#baseState": {
templateUrl: "viewB.html"
controller: "ViewBCtrl"
},
"viewC#baseState": {
templateUrl: "list.html"
controller: "listCtrl"
}
}
})
.state('baseState.create', function() {
url: "/create",
views: {
"viewA#baseState": {
templateUrl: "viewA.html"
controller: "ViewACtrl"
},
"viewB#baseState": {
templateUrl: "viewB.html"
controller: "ViewBCtrl"
},
"viewC#baseState": {
templateUrl: "create.html"
controller: "createCtrl"
}
}
})
To achieve that you basically need to freeze your viewA and viewC at the level of baseState and make that state abstract:
.state('basestate', {
url: '/basestate',
abstract: true,
views: {
"viewA": {
templateUrl: "viewA.html",
controller: "ViewACtrl"
},
"viewB": {
templateUrl: "viewB.html",
controller: "ViewBCtrl"
},
"viewC": {
template: '<div ui-view="viewC_child"></div>'
}
}
})
Note that for viewC we are making a placeholder that will contain our nested view (either list or create):
.state('basestate.list',{
url: "/list",
views: {
"viewC_child": {
templateUrl: "list.html",
controller: "ListCtrl"
}
}
})
.state('basestate.create', {
url: "/create",
views: {
"viewC_child": {
templateUrl: "create.html",
controller: "CreateCtrl"
}
}
})
Check this plunkr and be careful with commas in your code :)

Categories

Resources