Resolving state in AngularJS - angularjs

I need to get some content data to my controller:
state('admin.businesses.employees.all', {
resolve: {
executorsListTitle: 'All employees',
executorsEmptyListMessage: 'Add the first employee'
},
url: '/all',
controller: 'ExecutorsController',
templateUrl: 'templates/admin/executors/index.html'
})
And a controller code:
module.controller(
'ExecutorsController',
[
'$scope', '$rootScope', '$state',
'$stateParams', '$modal', 'executorsListTitle',
'executorsEmptyListMessage', 'Executor',
function($scope, $rootScope, $state, $stateParams, $modal, executorsListTitle, executorsEmptyListMessage, Executor) {
// Some code
}
)
But when I try to get into this state I can't do it - click by button makes nothing; if I remove resolve from state description it works good. What I do wrong? Thanks!

The resolve of the state machine expects a key and a factory. The doc states:
key – {string}: a name of a dependency to be injected into the controller.
factory - {string|function}
And when you provide a string to the factory:
If string, then it is an alias for a service.
If you want to return a string, you can do the following:
state('admin.businesses.employees.all', {
resolve: {
executorsListTitle: function() {
return 'All employees';
},
executorsEmptyListMessage: function() {
return 'Add the first employee';
},
},
url: '/all',
controller: 'ExecutorsController',
templateUrl: 'templates/admin/executors/index.html'
})
If you are using static data (the strings you are resolving to), you can also use the custom data property:
state('admin.businesses.employees.all', {
data: {
executorsListTitle: 'All employees',
executorsEmptyListMessage: 'Add the first employee'
},
url: '/all',
controller: 'ExecutorsController',
templateUrl: 'templates/admin/executors/index.html'
})
If you use this method, in the controller you can access the data like this:
$state.current.data.executorsListTitle
You can use strings directly with this method. Here is the doc for the custom data property.

Related

Example of using a parameter passed through $state.go

Can someone explain how to use parameters sent with $state.go? In CreatePollController I create a poll which I send to the state add_data_poll (AddDataPollController), but I really don't know how to access this parameter to display it in the view or use it in the controller (I tried to see the response with console.log($scope.response), but it doesn't work), can anyone explain me?
angular.module('estudios')
.controller('CreatePollController', ['$scope', 'Restangular', '$state',
function($scope, Restangular, $state) {
$scope.addPoll = function() {
if ($scope.allow_anonymous_answer == null)
$scope.allow_anonymous_answer = false
var poll = {title: $scope.title, description: $scope.description, allow_anonymous_answer: $scope.allow_anonymous_answer, initial_message: $scope.initial_message, final_message: $scope.final_message};
Restangular.all('polls').post(poll).then(function(response) {
$state.go('add_data_poll', response);
});
};
}])
.controller('AddDataPollController', ['$scope', 'Restangular',
function($scope, Restangular) {
}]);
And these are the corresponding states.
.state('create_poll', {
url: '/create_poll',
parent: 'home',
templateUrl: 'poll/create_poll.html',
controller: 'CreatePollController'
})
.state('add_data_poll', {
url: '/create_poll/add_data_poll',
parent: 'home',
templateUrl: 'poll/add_data_poll.html',
controller: 'AddDataPollController'
You need to have either params defined in your state or query params defined in your state url.
Example for state params:
.state('add_data_poll', {
url: '/create_poll/add_data_poll',
params: {
// define object with parameters that you want to pass
// Example:
id: 1 // 1 is the default parameter if no id is passed
}
parent: 'home',
templateUrl: 'poll/add_data_poll.html',
controller: 'AddDataPollController'
This way you can send parameters but they won't be available in the query string and upon refresh they will be lost.
Example for defining query parameters:
.state('add_data_poll', {
url: '/create_poll/add_data_poll?someParameter&anotherOne',
parent: 'home',
templateUrl: 'poll/add_data_poll.html',
controller: 'AddDataPollController'
someParameter and anotherOne will be available if you pass them from the incoming state.
When passing parameters you should define what parameters you are passing.
$state.go('some.route', {id: 2, someParam: 'coolParam');
And then you can access them with $stateParams in the controller. But first you need to inject it.
myApp.controller('myCtrl', function($stateParams) {
console.log($stateParams);
});
It is not good idea to pass the whole response from an API. Better will be if you choose just the stuff you need from the response and build your state around them.
Read more about ui-router state params HERE

How to pass two parameters in route ui

I have controller that needs to receive two id values. One id value identifies a vendor and the second identifies an event (eventId and VendorId).
My current state is as such.
.state('/vendordetail', {
url: '/vendordetail/:vendorId',
templateUrl: '/home/vendordetail',
controller: 'VendorDetailController',
resolve: {
vendorId: ['$stateParams', function ($stateParams) {
return $stateParams.vendorId;
}],
vendorPreload: ['$stateParams', 'vendorDetailRepo', '$state', function ($stateParams, vendorDetailRepo, $state) {
if ($stateParams.vendorId != "")
return vendorDetailRepo.get({ id: $stateParams.vendorId }).$promise;
}]
}
});
At the moment I am able to take the vendorId. But I would like to include an eventId in the state. Can anyone help me modify my state to take the second parameter (eventId) ?
Thank you.
First oft all I would advice you to put your parameters as url-parameters if you don't have good reasons against it.
Following this advice your state may look as follows:
state('/vendordetail', {
url: '/vendordetail?:vendorId:eventId',
templateUrl: '/home/vendordetail',
controller: 'VendorDetailController',
resolve: {
vendorId: ['$stateParams', function ($stateParams) {
return $stateParams.vendorId;
}],
eventId: ['$stateParams', function ($stateParams) {
return $stateParams.eventId;
}],
vendorPreload: ['$stateParams', 'vendorDetailRepo', '$state', function ($stateParams, vendorDetailRepo, $state) {
if ($stateParams.vendorId != "")
return vendorDetailRepo.get({ id: $stateParams.vendorId }).$promise;
}]
}
});
By the way: you don't need to resolve the parameters. You can simply inject $stateParams into your controller.
url: '/vendordetail/:vendorId'/:eventId,
Not sure why you have a vendorId in the resolve as well as the url part. As long as $stateParams is injected into your controller, you can access them that way.

ui-router: Integrating with existing controllers

I am in the process of converting my current angular project to use ui-router and I am a little confused. The documentation states I add my controller as such:
$stateProvider.state('contacts.detail', {
url: '/contacts/:contactId',
controller: function($stateParams){
$stateParams.contactId //*** Exists! ***//
}
})
I have defined my old controller in this manner:
xap.controller('DemoCtrl', [$scope, function ($scope, demoService) {
})
where xap is defined as:
var xap = angular.module({ .... })
What is the correct integration method?
Thanks
You can refer to a pre-registered controller by name:
$stateProvider.state('contacts.detail', {
url: '/contacts/:contactId',
controller: 'DemoCtrl'
});
You can add the $stateParams dependency to your controller to access parameters:
xap.controller('DemoCtrl', [
'$scope',
'$stateParams',
'demoService',
function ($scope, $stateParams, demoService) {
$stateParams.contactId //*** Exists! ***//
}
]);
But you can also inline your controllers and therefore not have to come up with unique names for each controller for every state:
$stateProvider.state('contacts.detail', {
url: '/contacts/:contactId',
controller: [
'$scope',
'$stateParams',
'demoService',
function ($scope, $stateParams, demoService) {
$stateParams.contactId //*** Exists! ***//
}
]
});
The controller in the state is not a resolve field.
In the state, you have to put only controller name because when you declare it, it's "injected" into your angular module.
So, you have to put controller name like this :
$stateProvider.state('contacts.detail', {
url: '/contacts/:contactId',
controller: 'ContactsCtrl'
});
If you want to inject some variable, you can add an object in the state like this :
$stateProvider.state('contacts.detail', {
url: '/contacts/:contactId',
controller: 'ContactsCtrl',
myVar: function(...){
return '...';
}
});
So, if you put a function, it's for a resolve field and not for controllers... You can implement it into state but it's better to do it outside state declaration.

Accessing parameters in parent state

I have the following setup in my AngularJS app:
.state('people.view',
{
abstract: true,
parent: 'people',
views: {
'header#maincontent': {
templateUrl: 'partials/people/_header_view.html'
},
'footer#maincontent': {
templateUrl: 'partials/people/_footer_view.html'
}
}
})
.state('people.details',
{
parent: 'people.view',
url: '/:personId/details',
views: {
'content#maincontent': {
templateUrl: 'partials/people/details.html',
controller: 'PeopleDetailCtrl'
}
}
})
.state('people.addressbook',
{
parent: 'people.view',
url: '/:personId/addressbook',
views: {
'content#maincontent': {
templateUrl: 'partials/people/addressbook.html',
controller: 'PeopleAddressBookCtrl'
}
}
})
So I have a Detail and an Address Book view that are children of a Person View state that has a header and footer (that don't change).
But because the personId is only passed in the child states and only they have a controller specified, then it means I can't access the person information.
For example in the header I want to show the person name.
How can I do this?
Based on the answer below from #mohamedrias I have tried:
.controller('PeopleDetailCtrl', ['$scope', '$rootScope', '$stateParams', 'Person',
function($scope, $rootScope, $stateParams, Person) {
$scope.person = Person.get({personId: $stateParams.personId}, function(person) {
console.log(person);
$rootScope.person.firstname = person.firstname;
$rootScope.person.lastname = person.lastname;
});
}]);
So that I can access {{person.firstname}} in the header, but I get the error:
TypeError: Cannot set property 'firstname' of undefined
The console shows:
Resource {firstname: "Cameron", lastname: "Drysdale", $promise: Object, $resolved: true, $get: function…}
In your child controller, emit the event along with personId.
$scope.$emit('personId', personId);
In your parent controller:
$scope.$on('personId', function(event, personId) {
// check for personId and process the information
});
The above is nice way of doing it.
Else you can do in normal way too, but it's not recommended.
Inject $rootScope in your child controller:
app.controller("ChildController", function($scope, $rootScope, $routeParams) {
$rootScope.personId = $routeParams.personId;
});
In your template header, you can just refer to personId and it will pick the value from $rootScope.
Update based on your code:
$rootScope.person = $rootScope.person || {};
$rootScope.person.firstname = person.firstname;
This is just to make sure that $rootScope.person is available.

ui router resolve is throwing error provider not found

I have got a ui -router state here
var AccountParentState = {
url: "/Account",
views: accountrootview,
stickA: true,
},
AccountAddState = {
url: "/add",
views: addaccountview,
controller: "account-controller",
resolve: {
Name: function () {
return "Joydeep";
}
}
};
$stateProvider
.state('account', AccountParentState)
.state("account.add", AccountAddState)
And this is my controller :
angular.module('ngApp').controller('account-controller', ['$scope', '$state', "account", "plugin-factory", "Name", function ($scope
, $state
, account
, plugins, Name) {
console.log(Name);
}]);
When I am trying to resolve the Name within the account-controller . Its throwing the error as :
Unknown provider: NameProvider <- Name <- account-controller
My question is how to resolve this situation . Or resolve the data within the ui-router state using resolve property .
To help you to see the issue, I created working plunker, which does use similar definition to the above states:
var AccountParentState = {
url: "/Account",
views: { '' :
{ template: 'Account state <hr/><div ui-view=""></div>',} },
stickA: true,
},
AccountAddState = {
url: "/add",
//views: addaccountview,
templateUrl: 'tpl.html',
controller: "account-controller",
resolve: {
Name: function() {
return "Joydeep";
}
}
};
$stateProvider
.state('account', AccountParentState)
.state("account.add", AccountAddState)
Factories and controller:
.factory('account', function(){return {}})
.factory('plugin-factory', function(){return {}})
.controller('account-controller',
['$scope', '$state', "account", "plugin-factory", "Name"
, function($scope, $state, account, plugins, Name) {
console.log(Name);
}
])
And that is working, because controller was instantiated by the UI-Router, as a part of the state transition.
If, on the other hand, we will extend that example with this (see forked broken version) line in the index.html (outside of the state def)
<div ng-controller="account-controller"></div>
<div ui-view=""></div>
The issue will appear. Why? Because now the controller is not managed by the UI-Router. It is not injected by its infrastructure, not provided with configured value 'Name'. It is "plain angular" style..
Check the working solution here and the broken here

Resources