Can I group multiple objects in UI router resolve - angularjs

I need to load 3 services up front in Resolve , rather than creating seperate service calls for each, will it be possible to return a object of functions
My router
.state('home.movies', {
parent: 'home',
url: '/home/movies/edit/:id',
data: {
roles: []
},
views: {
'content#': {
templateUrl: 'views/admin/activity-edit.html',
controller: 'ActivityEditController'
}
},
resolve:
titles:function (MovieService){
return {
actors: function (MovieService) {
return MovieService.getActors('','','N');
},
actresses:function (MovieService) {
return ResourceService.getActresses();
},
timemap:function(MovieService){
return MovieService.getTimemap();
}
}
}
});
})
my Controller
.controller('MovieEditController', function ($scope,titles,MovieService) {
refere is as
$scope.moviesActors=titles.actors;

It's possible with $q:
resolve: {
titles: function (MovieService, $q){
return $q.all({
actors: MovieService.getActors('','','N'),
actresses: ResourceService.getActresses(),
timemap: MovieService.getTimemap()
});
}
}
Resolved titles will look like: { actors: [], actresses: [], timemap: {} }

Related

How to load Angular-translate before any UI is displayed with ui-router resolve

I used angular-translate for i18n. I want to use $translatePartialLoader service to modular language key as lazy load. Also I want to use ui-router resolve option for this.
Now How to do this? Is possible add a code sample for me?
Thanks
I find solutions and solve my problem.
In config:
$translatePartialLoaderProvider.addPart('index');
$translateProvider
.useSanitizeValueStrategy(null)
.fallbackLanguage('en-us')
.registerAvailableLanguageKeys(['en-us','pt-br'], {
'en_*': 'en-us',
'pt_*': 'pt-br'
})
.useLoader('$translatePartialLoader', {
urlTemplate: '{part}/locale_{lang}.json'
})
.useLoaderCache(true)
.useCookieStorage()
.determinePreferredLanguage();
In ui-router for index:
.state('index', {
url: '/index',
templateUrl: 'index.html',
controller:'IndexCtrl',
resolve: {
trans:['RequireTranslations',
function (RequireTranslations) {
RequireTranslations('index');
}],
dep: ['trans','$ocLazyLoad',
function(trans,$ocLazyLoad){
return $ocLazyLoad.load(['plugin']).then(
function(){
return $ocLazyLoad.load(['IndexCtrl.js']);
}
);
}]
}
})
.state('index.users',{
url: "/users",
templateUrl: "users.html",
controller:'UserListCtrl',
resolve: {
trans:['RequireTranslations',
function (RequireTranslations) {
RequireTranslations('modules/user');
}],
dep: ['trans','$ocLazyLoad',
function(trans,$ocLazyLoad){
return $ocLazyLoad.load(['UserListCtrl.js'])
}]
}
})
and in run:
app.run(function($rootScope,$translate) {
// translate refresh is necessary to load translate table
$rootScope.$on('$translatePartialLoaderStructureChanged', function () {
$translate.refresh();
});
$rootScope.$on('$translateChangeEnd', function() {
// get current language
$rootScope.currentLanguage = $translate.use();
});
})
and in RequireTranslations factory:
app.factory('RequireTranslations', function($translatePartialLoader, $translate,$rootScope) {
return function() {
angular.forEach(arguments, function(translationKey) {
$translatePartialLoader.addPart(translationKey);
});
return $translate.refresh().then(
function(){
return $translate.use($rootScope.currentLanguage);
}
);
};
});
and please note you should add $translatePartialLoader and trans as parameter in all controllers like this:
app.controller('UserListCtrl',function($scope,...,$translatePartialLoader,trans){

Angular UI + UI Router: How to inherit Resolved states

I have a parent state with 3 child states. The parent state retrieves data using promises and returns resolved data in an object (named 'data') so it is accessible to controller and views. Some child states need the resolved parent data also to define their own object named data. But it seems that when transitioning from sibling states their resolves are never reached (a breakpoint in the corresponding state definition never gets hit).
In short: when transferring from state 'settings.account.person' to sibling state 'settings.account.password' I want the resolve statement to be executed. Currently it is not being hit at all...
States:
.state('settings.account', {
url: '/account'
,resolve: {
menu: ['menu','MenuService', function (menu,MenuService) {
return MenuService.retrieveSubMenuByParentUrl(menu,'/settings/account');
}],
account: ['UserManagementService',function(UserManagementService) {
return UserManagementService.account();
}],
data: ['menu',function (menu) {
return {menu:menu};
}]
}
,views: {
'setting#settings': {
templateUrl: '/app/components/settings/account/views/tabpanel.html'
,controller: 'AccountController'
}
}
})
.state('settings.account.person', {
url: '/person',
resolve: {
languages: ['APIService',function(APIService) {
return APIService.call(AppConfig.API_ENDPOINTS.language);
}],
data: ['menu','account','languages',function(menu,account,languages){
return {
menu: menu,
account: account,
languages: languages
};
}]
}
,views: {
'tabContent#settings.account': {
templateUrl: '/app/components/settings/account/views/person.html'
,controller: 'AccountController'
}
}
})
.state('settings.account.password', {
url: '/password'
,data: ['account',function(account){
return {
account: account
};
}]
,views: {
'tabContent#settings.account': {
templateUrl: '/app/components/settings/account/views/password.html'
,controller: 'AccountController'
}
}
})
.state('settings.account.delete', {
url: '/delete'
,data: ['account',function(account){
return {
id: account.id
};
}]
,views: {
'tabContent#settings.account': {
templateUrl: '/app/components/settings/account/views/deleteAccount.html'
,controller: 'AccountController'
}
}
})
Oops.. I see that in states 'settings.account.password' and 'settings.account.delete' I forgot half of the resolve block.... No wonder it doesn't get hit.

How to pass data from $state.go() to the data parameter in stateprovider in angular?

I am having trouble passing some data to the stateprovider using $state.go(). Here is the sample code that we have been using.
$stateProvider.state('socialform', {
url: "/socialform?webcontent",
templateUrl: "base_template/_Sends.html?",
data: { pageTitle: 'Social & Website Publishing' },
resolve: {
callPreRenderServices: callPreRenderServices
}
});
$scope.isWebContent = function(status) {
if(status) {
$state.go('socialform', {webcontent:true});
}
else {
$state.go('socialform');
}
};
Basically, what we need to be doing is to pass a title variable to $state.go() so that it will replace the pageTitle to whatever is the value of the passed variable.
From the code above to this:
$stateProvider.state('socialform', {
url: "/socialform?webcontent",
templateUrl: "base_template/_Sends.html?",
data: { pageTitle: title },
resolve: {
callPreRenderServices: callPreRenderServices
}
});
$scope.isWebContent = function(status) {
if(status) {
$state.go('socialform', {webcontent:true, title:"some title"});
}
else {
$state.go('socialform', {title:"another title"});
}
};
You could use a service :
module.service('titleService', function() {
this.title = null;
});
// ... inject titleService in the calling controller ...
$scope.isWebContent = function(status) {
if(status) {
titleService.title = 'Some Title'
$state.go('socialform');
}
else {
titleService.title = 'Another Title'
$state.go('socialform');
}
};
Then, you can either inject it in via custom data or, via the resolve function :
// ... inject before route definition, via dependency injection
data = { title: titleService.title };
$stateProvider.state('socialform', {
url: "/socialform?webcontent",
templateUrl: "base_template/_Sends.html?",
// like this
data: data,
resolve: {
callPreRenderServices: callPreRenderServices
// Or you can resolve your title from your service
// and use pageTitle in your controller
pageTitle: ['titleService', function(titleService) {
return titleService.title;
}]
}
});
You could also pass it as a $state parameter :
$stateProvider.state('socialform', {
url: "/socialform/:webcontent/:title",
// ...
});
// ...
$state.go('socialform', {webcontent: 'something', title: 'some other thing'});

UI-Router's resolve functions are only called once- even with reload option

In Angular ui router, when $state.go("main.loadbalancer.readonly"); is ran after main.loadbalancer.readonly has been previously activated, my resolve: {} is not being evaulauted/executed. The resolve is simply bypassed..I have verified this with the console.log($state.current.data['deviceId']); not showing.
angular.module("main.loadbalancer", ["ui.bootstrap", "ui.router"]).config(function($stateProvider) {
return $stateProvider.state("main.loadbalancer", {
url: "device/:id",
views: {
"content#": {
templateUrl: "loadbalancer/loadbalancer.html",
controller: "LoadBalancerCtrl"
}
}
}).state("main.loadbalancer.vips", {
resolve: {
isDeviceReadOnly: function($state) {
console.log($state.current.data['deviceId']);
if (!$state.current.data['deviceId']) {
console.log("pimp");
$state.go("main.loadbalancer.readonly");
}
}
},
url: "/vips",
templateUrl: "loadbalancer/vip-table.html",
controller: "VipListCtrl"
}).state("main.loadbalancer.readonly", {
url: "/readonly",
templateUrl: "loadbalancer/readonly.html",
controller: "ReadonlyCtrl"
});
});
Controller code:
submit = function() {
$state.current.data = { deviceId: false };
return LoadBalancerSvc.searchDevice($scope.searchInput.value).get().then(function(lb) {
console.log(lb.ha_status);
if (lb.ha_status == "secondary") {
console.log("hi");
$state.current.data['deviceId'] = false;
$state.go("main.loadbalancer.readonly"); //WHEN THIS IS RAN A SECOND TIME
AFTER STATE HAS BEEN ACTIVE BEFORE
$state.deviceReadonly = true
} else {
$state.current.data['deviceId'] = lb.id;
$state.deviceReadonly = false;
SearchSvc.updateDeviceNumber(lb.id);
$state.go("main.loadbalancer.vips", {id: lb.id});
console.log("bye");
}
});
};
I can only guess that since main.loadbalancer.vips has been activated previously, then to ui router it means once resolved always resolved. How can I make it to where each time the state is activated with $state.go("main.loadbalancer.readonly") resolve will be evaluated?
Note: I have also tried $state.go("main.loadbalancer.readonly", { reload: true }); to no success.
It seems that 'transitionTo' works instead.
if (lb.ha_status == "secondary") {
$state.current.data['deviceId'] = false;
$state.transitionTo("main.loadbalancer.readonly", {}, { reload: true });
$state.deviceReadonly = true
}

how can I pass a service to a controller dynamically by some conditions

I am using the ui-router module and have defined these states:
.state('projects.create', {
url: '/create',
views: {
'outer#': {
templateUrl: 'views/projects.create.html',
resolve: {
schoolyear: function(schoolyearService) {
return schoolyearService.createSchoolyear();
}
},
controller: 'ProjectWizardController'
}
}
})
.state('projects.edit', {
url: '/edit',
views: {
'outer#': {
templateUrl: 'views/projects.edit.html',
resolve: {
schoolyear: function(schoolyearService) {
return schoolyearService.editSchoolyear();
}
},
controller: 'ProjectWizardController'
}
}
})
As each of both ui-router states know which states they are they also know what dependencies should be passed to the ProjectWizardController.
When the projects.create state is activated I want to pass the CreateWizardDataService to the ProjectWizardController.
When the projects.edit state is activated I want to pass the EditWizardDataService to the ProjectWizardController.
HOW can I manually inject the service dependency into the ProjectsWizardController?
'use strict';
angular.module('schoolyearProjectModule').controller('ProjectWizardController',
function ($scope, wizardDataService, $state, schoolyear) {
// wizardDataService => could be the CreateWizardDataService or EditWizardDataService
// The wizardDataService is the individual service for an AddService or EditService
// service contain the 3 same main properties: schoolyearData, schoolclasscodesData, timetableData
wizardDataService.schoolyearData = schoolyear.schoolyearData;
wizardDataService.schoolyearData = schoolyear.schoolclassCodesData;
wizardDataService.schoolyearData = schoolyear.timetableData;
// The if and else if should be injected into this Controller becaue the outside ui router states know their state edit/create
if ($state.current.name === 'projects.create') {
$scope.steps = [wizardDataService.schoolyearData, wizardDataService.schoolclassCodesData, wizardDataService.timetableData];
}
else if ($state.current.name === 'projects.edit') {
$scope.steps = [wizardDataService.schoolyearData, wizardDataService.schoolclassCodesData, wizardDataService.timetableData];
}
$scope.steps = [wizardDataService.schoolyearData, wizardDataService.schoolclassCodesData, wizardDataService.timetableData];
$scope.activeStep = $scope.steps[0];
$scope.step = 0;
var stepsLength = $scope.steps.length;
$scope.isLastStep = function () {
return $scope.step === (stepsLength - 1);
};
$scope.isFirstStep = function () {
return $scope.step === 0;
};
$scope.getCurrentStep = function () {
return $scope.activeStep.name;
};
$scope.getNextLabel = function () {
return ($scope.isLastStep()) ? 'Submit' : 'Next';
};
$scope.previous = function () {
if ($scope.step > 0) {
$scope.step--;
$scope.activeStep = $scope.steps[$scope.step];
}
};
$scope.next = function () {
if ($scope.isLastStep() && $scope.activeStep.isValid()) {
$state.go('^');
}
else if ($scope.activeStep.isValid()) {
$scope.step += 1;
$scope.activeStep = $scope.steps[$scope.step];
}
}
});
You have two ways to do this:
Option 1 - Use resolve with a string as the value. As per the documentation:
The resolve property is a map object. The map object contains
key/value pairs of:
key – {string}: a name of a dependency to be injected into the
controller.
factory - {string|function}: If string, then it is an
alias for a service. Otherwise if function, then it is injected and
the return value is treated as the dependency. If the result is a
promise, it is resolved before the controller is instantiated and its
value is injected into the controller.
Option 1 example:
.state('projects.create', {
url: '/create',
views: {
'outer#': {
templateUrl: 'views/projects.create.html',
resolve: {
schoolyear: function(schoolyearService) {
return schoolyearService.createSchoolyear();
},
wizardDataService: 'CreateWizardDataService'
},
controller: 'ProjectWizardController'
}
}
})
.state('projects.edit', {
url: '/edit',
views: {
'outer#': {
templateUrl: 'views/projects.edit.html',
resolve: {
schoolyear: function(schoolyearService) {
return schoolyearService.editSchoolyear();
},
wizardDataService: 'EditWizardDataService'
},
controller: 'ProjectWizardController'
}
}
})
Option 2 - Use $injector.get('CreateWizardDataService') or $injector.get('EditWizardDataService') directly in your controller depending on which state you are in.

Resources