resolve is not passing data from factory to controller - angularjs

I am newbie to resolve function in ui-router and i am not getting answer for call to factory whereas i get the value if i just simply pass a string.
I tried console.log for factory and i am getting an output.
State Function
.state('trainer.classes',
{ url: "/trainer/classes",
controller:"trainerClassesCntrl",
templateUrl: "views/trainer/trainer.classes.tpl.html",
resolve : {courses : function(courseFactory){
courseFactory.get().then(function(response){
// console.log(response); //Getting output
return response;
});
// return "asdf"; //Getting output as test case.
}
},
permissions:{allow : ['trainer']}
})
Controller
myApp.controller('trainerClassesCntrl',['$scope','apiService','$rootScope','courses',function($scope,apiService,$rootScope,courses){
console.log(courses); // undefined for coursesFactory return and asdf for simple return.
}]);

You are not returning the promise. Try something like this:
.state('trainer.classes', {
url: "/trainer/classes",
controller: "trainerClassesCntrl",
templateUrl: "views/trainer/trainer.classes.tpl.html",
resolve: {
courses: function(courseFactory){
return courseFactory.get();
}
},
permissions: {
allow: ['trainer']
}
})
You can read more about using resolves with ui-router here:
https://github.com/angular-ui/ui-router/wiki#resolve

Related

angular 1.5 component wait data

i am trying to use au component in order to display my data.
In my template i have :
{{myDatas}}
<my-cmp data="myDatas"></my-cmp>
i displayed {{myDatas}} to be sure there was data
here is my code for my component :
(function() {
'use strict';
angular
.module('myApp.test')
.controller('TestController', TestController)
.component('myCmp', {
templateUrl: 'myTemplate.html',
bindings: {
data: '='
},
controller: myController
});
function TestController($scope, $stateParams, ResidencesFactory) {
$scope.myDatas = TestFactory.read({id: $id});
}
function myController($scope) {
console.log($scope.$ctrl.data.nbElements);
}
})();
This code doesn't works.
But if i replace $scope.myDatas with the expected JSON, it works.
here is the code of TestFactory :
(function () {
'use strict';
angular
.module('core.test')
.factory('TestFactory', TestFactory);
function TestFactory($resource) {
return $resource(
'/api/test/:id',
{
id: '#id'
},
{
query: {
method: 'GET',
isArray: true
},
read: {
method: 'GET'
}
}
);
}
})();
So i think i have to wait the data from the $resource of my TestFactory but how can i do this ?
Thanks
EDIT
here is what i did. i replaced
$scope.myDatas = TestFactory.read({id: $id});
with
TestFactory.read({id: $id}).$promise.then(function(response){
$scope.myDatas = response;
});
And in my component controller, i had the $onInit like this :
this.$onInit = function () {
console.log($scope.$ctrl.data);
$scope.percent = parseFloat(($scope.$ctrl.data.nbElements/ $scope.$ctrl.data.nbAllElements * 100).toFixed(2))
}
But in the chrome console, it tells me that $scope.$ctrl.data is undefined, and the error "TypeError: Cannot read property 'nbElements' of undefined
if i do
console.log($scope.$ctrl);
i have this in chrome console :
>myController
>$onInit: function()
>data: m
>__proto__:Object
Chrome tell me myCotroller was evaluated so i think myCotroller is not waiting the data before building my properties. What am i doing wrong ?
problem solved adding an ng-if condition in my template
<my-cmp ng-if="myDatas" data="myDatas"></my-cmp>
thanks for your help

Angular factory and controller

I am trying to learn about using factory with controller. I have seen one example with:
angular.module('flapperNews')
.factory('posts', ['$http', function($http) {
var o = {
posts: []
}
o.getPosts = function() {
return $http.get('api/posts').success(function(data) {
return data
})
};
o.create = function(post) {
return $http.post('api/posts', post).success(function(data) {
o.posts.push(data);
})
};
return o
}])
When I console.log(o.getPosts()), it returned the following:
Promise {$$state: Object}
$$state
:
Object
pending
:
undefined
processScheduled
:
false
status
:
1
value
:
Object
config
:
Object
data
:
Array[6]
0
:
Object
_id
:
"576d4904f2aa867dadb7b286"
link
:
"aaa"
title
:
"nice weather in Australia"
upvotes
:
0
__proto__
:
Object
__defineGetter__
:
__defineGetter__()
__defineSetter__
:
__defineSetter__()
__lookupGetter__
:
__lookupGetter__()
__lookupSetter__
:
__lookupSetter__()
constructor
:
Object()
hasOwnProperty
:
hasOwnProperty()
isPrototypeOf
:
The data I wanted is under Array[6] which is under $$state, does anyone have any idea what this is and how does one normally extract that data?
The data is supposed to be passed to my controller like so:
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'views/posts.html',
controller: 'PostCtrl',
controllerAs: 'posts',
resolve: {
postPromise: ['posts', function(posts) {
console.log(posts.getPosts())
return posts.getPosts();
}]
}
});
Note:This is taken from an online tutorial. Would really appreciate it if someone can shed some light on this as I am new to factory etc. The current code doesn't return anything to my view, can you tell me where I have gone wrong?
Edited/Added: This is the implementation of controller. When I console.log(posts.posts) it returns an empty array []. Any ideas?
angular.module('flapperNews')
.controller('PostCtrl', [
'$scope','posts',
function($scope,posts){
$scope.posts=posts.posts;
$scope.incrementUpvotes=function(post){
post.upvotes+=1
}
$scope.addPost = function(){
if(!$scope.title || $scope.title === '') { return; }
posts.create({
title: $scope.title,
link: $scope.link,
});
$scope.title = '';
$scope.link = '';
};
}]);
How are you calling the factory's method in your controller? You are making an $http request which returns a promise.
You can learn about promises here:http://andyshora.com/promises-angularjs-explained-as-cartoon.html.
In short you can see promises as functions that execute right away but return data in the future (not right away). You will have to wait until the promise "resolves" to get the data. That is why is good to wrap any code that needs data from a promise, within the promise function itself.
In your controller you should call the factory method(getPosts()) like this:
posts.getPosts().then(function(response){
$scope.news = response.data; <---here is where you get your data for your news. You cant not declare **$scope.data** outside this promise function because you will miss the data.
});
Don't forget to inject your posts service/factory in your controller like this:
controller(['posts',function(posts){ ... });
You can also get the data in your route like this:
$stateProvider
.state('home',{
url:'/home',
templateUrl:'views/posts.html',
controller:'PostCtrl',
controllerAs:'posts',
resolve:{
postPromise: ['posts', function(posts){
return posts.getPosts().then(function(response){
return response.data
});
}]
}
})
Then in your controller you can inject the postPromise like this:
controller(['postPromise',function(postPromise){ ... });
Now you can assign the data to a variable in your controller like this:
$scope.news = postPromise;
Hope I answered your question. If I misunderstood please give more details or provide a codepen.

Why can I not chain promises in a route 'resolve'?

I am trying to chain the promise that fetches 'dtaDashboard' to use a value from the fetched dashboard, to execute a second call. For some reason the promise chain does not seem to work inside a 'resolve'. Why not?
state('uploadServiceTxData', {
url: '/dashboard/:id/upload',
templateUrl: 'views/dashboard-upload.html',
controller: 'DashboardUploadController',
resolve: {
dtaRefData: function(RefDataService) {
return RefDataService.getRefData();
},
dtaDashboard: function(DashboardService, $stateParams) {
return DashboardService.get({ id: $stateParams.id });
},
dtaUploads: function(TransactionSummaryUploadService, dtaDashboard, $q) {
return dtaDashboard.then(function(dashboard) { return TransactionSummaryUploadService.findByExample({ service: dashboard.service.name }) });
}
}
});
Some more information on the code above. The functions on the DashboardSerivce and TransactionSummaryUploadService, are implemented with $resource. So "get" and "findByExample" use $resource to make REST calls.
You are very close.
dtaDashboard has already been resolved when it's injected into datUploads. So you use the resolved result (meaning it's no longer a promise).
state('uploadServiceTxData', {
url: '/dashboard/:id/upload',
templateUrl: 'views/dashboard-upload.html',
controller: 'DashboardUploadController',
resolve: {
dtaRefData: function(RefDataService) {
return RefDataService.getRefData();
},
dtaDashboard: function(DashboardService, $stateParams) {
return DashboardService.get({ id: $stateParams.id });
},
dtaUploads: function(TransactionSummaryUploadService, dtaDashboard, $q) {
return TransactionSummaryUploadService.findByExample({ service: dtaDashboard.service.name });
}
}
});
The reason it did not work is that the services were implemented with $resource. The methods of $resource do not return promises, they return an object which contains a promise, and some other things. To get to the promise itself, I needed to use dtaDashboard.$promise.
So code like this works:
dtaDashboard: function(DashboardService, $stateParams) {
return DashboardService.get({ id: $stateParams.id });
},
dtaUploads: function(dtaDashboard) {
dtaDashboard.$promise.then(function(result) { ... /* result contains the data now. */ });
}
return DashboardService.get({ id: $stateParams.id });
Does not return the promise from the $resource service, it returns an object containing the promise (and eventually the data); that object is resolved, but not the promise it contains. To ensure that the route resolves to the data, this can be done instead:
dtaDashboard: function(DashboardService, $stateParams) {
return DashboardService.get({ id: $stateParams.id }).$promise;
}
Now dtaDashboard will be fully resolved to the data wherever it is injected.

Firebase + angularfire getting current user before controller loads

I'm following the official examples to fetch the user before the angular controller is fired but the controller is never fired when using this method. If I remove the resolve: state_resolver line the controller fires which means my resolver has something wrong. Any ideas what am I doing wrong here?
.config(function($stateProvider) {
var state_resolver;
state_resolver = {
"current_user": [
"simpleLogin", function(simpleLogin) {
return simpleLogin.$getCurrentUser();
}
]
};
return $stateProvider.state("dash", {
url: "/dash",
templateUrl: "templates/dash.html",
controller: "DashCtrl",
resolve: state_resolver
});
});
If the following example using $timeout works, then you probably have an issue with your simpleLogin service which does not respond.
.config(function($stateProvider) {
var state_resolver;
state_resolver = {
"current_user": function($timeout) {
return $timeout(function () {console.log('OK');}, 5000);
}
};

How to create an object with properties in the resolve parameter in the route provider in Angular?

I want to pre-load data in my controller. I am doing this using resolve in the routeprovider:
.when('/customers', {
controller: 'CustomerController', templateUrl: '/Customer/Index', resolve: {
countries: CustomerController.loadCountries,
genders: CustomerController.loadGenders,
}
})
As you can see I have two objects which will be injected into my controller, countries and gender. All this works fine.
What I want to do is, I want those objects to be part of one object: listData. I've tried:
.when('/customers', {
controller: 'CustomerController', templateUrl: '/Customer/Index', resolve: {
listData: {
countries: CustomerController.loadCountries,
genders: CustomerController.loadGenders
}
}
})
but this doesn't work: Argument 'fn' is not a function, got Object.
What is the right syntax / approach to accomplish this?
If you pass an object to a key, you must have a function as the value :
listData: function () {
// you need to inject
var deferred = $q.defer();
var listData = {};
// these should be services, btw !
CustomerController.loadCountries.then(function (countries) {
listData.countries = countries;
// resolve when you have both
if (listData.genders) deferred.resolve(listData);
});
CustomerController.loadGenders.then(function (genders) {
listData.genders = genders;
if (listData.countries) deferred.resolve(listData);
});
return deferred.promise;
}

Resources