ng.module('app')
.service('CardService', ['$http', CardService])
function CardService($http) {
this.$http = $http;
var self = this;
$http.get('http://localhost:3000/db').success(function(data) {
self.items = data;
console.log(self.items);
});
console.log(self.items);
}
CardService.prototype.list = function() {
console.log(self.items);
return this.items;
};
and result
service.js:14 undefined
service.js:18 undefined
service.js:18 undefined
service.js:12 [Object, Object, Object]
How do I solve this problem?
The ajax call is async. It will allow the thread to move on while it waits for a response from the .get
the console.logs you are doing will then be called in this order.
console.log right below your ajax call
console.log inside list prototype
(inside ajax success)
console.log inside list prototype
console.log below self.items = data
Not the angular way, but... the prototype should used only when the list is initialized inside the ajax call.
According to best practices, you should do all the http request related stuff to get data using factory or service. As it is asynchronous flow, $q shall be used to handle it. So your functionality would be done as given below. Kindly correct me if i have misinterpreted your question.
app.factory('CardService',function($http,$q) {
var obj = {};
obj.getCardServiceData = function(){
var defer = $q.defer();
$http.get('http://localhost:3000/db').then(function(response) {
defer.resolve(response.data);
},function(error){
defer.reject(error);
});
return defer.promise;
}
return obj;
});
app.controller('YOUR CONTROLLER',function($scope,CardService){
CardService.getCardServiceData().then(function(response){
$scope.self = response.data;
console.log($scope.self);
},function(error){
alert("There seems to be some error!");
console.error(error);
});
});
Related
The code below is contrived. I'm simplified things as best I could to ask the question.
I have a simple angular service that makes an API call and returns results:
doWork = function(reqId) {
return $http.get('/api/dowork/' + reqId).then(function(response) {
return response.data;
}).catch(function(response) {
return $q.reject(response.data);
});
}
mediumRequest = function() {
var req = 'medium';//normally do something hard to derive this value
return this.doWork(req);
}
In my controller, I can call the doWork function on the service and get back a good response like this:
myService.doWork('simple').then(function(response){
//do something great with response
});
However, if I need to call an intermediate method to preprocess the request, I get "Cannot read property 'then' of undefined":
myService.mediumRequest().then(function(response){
//do something great with response
});
Why doesn't the function mediumRequest return the promise that doWork returned to it?
Try this code , you did wrong in your service
var app = angular.module("myApp", [])
.service('myService',function($http,$q){
this.doWork = function(reqId) {
return $http.get('/api/dowork/'+ reqId).then(function(response) {
return response.data;
}).catch(function(response) {
return $q.reject(response.data);
});
};
this.mediumRequest = function() {
var req = 'medium';//normally do something hard to derive this value
return this.doWork(req);
};
})
app.controller("myCtrl", function($scope,$compile,myService) {
myService.doWork('simple').then(function(response){
console.log('b',response)
});
myService.mediumRequest().then(function(response){
console.log('a',response)
});
})
It will work
As with most things, the problem was a coding error in my actual service code. The code I've presented in this question would work as expected. I appreciate the couple of folks who offered suggestions of ways to identify the issue. Here was my issue:
My actual "intermediate" function had this structure:
mediumRequest = function(options) {
//process first option meeting criteria
options.forEach(function (item) {
if(item.meetsCriteria)
{
var req = item.code;
return this.doWork(req);
}
});
}
As you can see, the return is actually just exiting the forEach and never actually being returned from the mediumRequest function. Hence the error.
I have created a factory in my AngularJS application which is used to bring in refreshed data from server after a delete has been performed on one or more elements of the list.
var myApp = angular.module('app');
myApp.factory('mvListRefresher', function($http) {
return {
refreshCourses : function() {
var list = new Array();
$http.get('/api/courses').then(function(response) {
console.log('got refreshed lists');
console.log(response.data);
list = response.data;
}, function(error) {
console.log('error in retreiving fresh lists');
console.log(error);
});
console.log('Displaying list of courses');
console.log(list);
if(list.length != 0) {
return list;
}
}
}
});
I'm calling this factory in one of my controllers by calling
$scope.courses = mvListRefresher.refreshCourses();
But I'm getting an empty list, i.e I'm not getting any return value at all. In my factory function I observed that the line
console.log(list);
always prints out an empty array, however the line
console.log(response.data);
which is inside the success callback prints out the full list of objects correctly. I don't know how this is happening. I'm relatively new to AngularJS's promises and it's asynch methods and architecture. Kindly help me out. If you need any more info i'll provide it. I've done the entire app using MEAN. Thanks in advance!
$http requests are asynchronous by nature so at the point you're returning list, the request is not complete yet. You can read more about the general concepts of asynchronicity in JavaScript in this response: https://stackoverflow.com/a/14220323/704894
What you should do instead is return a Promise of list:
myApp.factory('mvListRefresher', function($http) {
return {
refreshCourses: function() {
return $http.get('/api/courses').then(function(response) {
return response.data;
});
}
};
});
$http methods return promises of results. Then you can use this function in the following way:
mvListRefresher.refreshCourses().then(function (list) {
$scope.courses = list;
});
You can read more about it in the $http documentation.
I want to load a JSON file into a factory and then return its value.
Here's the code:
angular.module('getGuilds', [])
.factory('getGuilds', getGuilds);
getGuilds.$inject = ['$http'];
function getGuilds($http){
var obj = {content:null};
$http.get('guild/guilds.json').success(function(data) {
obj.content = data;
});
return obj;
}
The problem is that it only returns the object with the value of null, so it seems the $http.get doesn't change the value of the obj.content.
After this I did a little test:
$http.get('guild/guilds.json').success(function(data) {
obj.content = data;
});
console.log(obj)
return obj;
}
It gave back this object insted of the JSON's array: {content:null}.
Then I put the console.log inside the $http.get request.
$http.get('guild/guilds.json').success(function(data) {
obj.content = data;
console.log(obj)
});
Guess what, it logged out the JSON file. Would somebody be so kind as to help me?
$http.get performs the get asynchronously. The code that appears after the success block in the source runs before the code within the success block. So it's behaving just as expected: on your first attempt, you're logging the results of an unfinished request.
This is because $http.get performs the get asynchronously. So at the point you were assigning the value, it wasn't available yet. You need to return the obj inside your success function changing your code like this should make it work:
// dataservice factory
angular
.module('getGuilds', [])
.factory('dataservice', dataservice);
dataservice.$inject = ['$http'];
function dataservice($http) {
return {
getGuilds: getGuilds
};
function getGuilds() {
return $http.get('guild/guilds.json')
.then(getGuildsComplete)
.catch(getGuildsFailed);
function getGuildsComplete(response) {
return response.data;
}
function getGuildsFailed(error) {
console.log('XHR Failed for getGuilds.' + error.data);
}
}
}
In your controller you would then call the dataservice:
dataservice.getGuilds()
.then(function(data) {
vm.guilds = data;
return vm.guilds;
});
Obviously the controller requires more code to actually work. But this should give you enough info to solve your issue.
In my controller I am calling a service with the following code:
Service.updateData(data).then(function (result) {
console.log(result);
});
In my service I am using $q to get multiple HTTP requests.
$rootScope.http_1 = $http.get();
$rootScope.http_2 = $http.get();
$q.all([$rootScope.http_1, $rootScope.http_2]).then(function(result) {
console.log(result[0], result[1]);
return result[0], result[1];
});
The code actually works as the http requests are successfully made. However, I get an error in the controller which says: TypeError: Cannot read property 'then' of undefined. I believe this is due the service not returning the promise in the correct way. Any ideas on how to resolve this would be much appreciated?
It looks like you are not returning the promise in updateData Try this:
updateData = function(data) {
$rootScope.http_1 = $http.get();
$rootScope.http_2 = $http.get();
return $q.all([$rootScope.http_1, $rootScope.http_2]);
}
You didn't return the promise, so there is nothing to call .then() on in your controller
You are returning inside the .then() function inside your service.updateData(), which doesn't do very much for you.
If you want to control it all inside the service and return a specific format, try this:
updateData = function(data) {
$rootScope.http_1 = $http.get();
$rootScope.http_2 = $http.get();
var defer = $q.defer();
$q.all([$rootScope.http_1, $rootScope.http_2]).then(function(result){
// process here to get the data how you want it, say in some new var foo
var foo = "some processed data based on result";
defer.resolve(foo);
});
return defer.promise;
}
I'm trying to store some user data in a service that will be accessible and modified across different controllers, and the data will be initially pulled via a $http call. Since the data has to be loaded, I've used promises in my previous code, but this can be quite irritating to write. For instance, even a basic getter function has to be written as the following
UserData.getData().then(function(data) {
//do something with the data
})
where UserData.getData() always returns a promise via deferred.promise (if the data has already been pulled, then resolve immediately). I'm wondering if there is anyway to split a) $http calls, and b) getter and setter methods into two different services so that if I call getter and setter methods from b), I don't need to wrap everything with then?
For instance, I'm trying to make UserFactory in charge of the $http call, and UserData in charge of getters and setters. However, I can't get the code to work since UserData.getData() will return undefined, and wondering if anyone can help? (I don't really want to have to use then everywhere).
angular.module('testApp', [])
//mocks a service that gets data from a server
.factory('UserFactory', function($timeout, $q) {
return {
getData: function() {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve({title: 'hello world'});
}, 1000);
return deferred.promise;
}
}
})
.factory('UserData', function(UserFactory) {
var data;
return {
//if already pulled, use existing data
getData: function() {
if (data) return data;
UserFactory.getData().then(function(res) {
data = res;
return data;
})
}
}
})
http://jsfiddle.net/QNLk2/1/
The then method is executed asynchronously so the return method as no effect there. That is why until the data has arrived every call to getData will return undefined.
You can try the following approach, where you can specify a callback if you want to be notified when data is ready, or simply wait for the data to be populated in the return variable.
.factory('UserData', function(UserFactory) {
var data = {};
return {
getData: function(callback) {
UserFactory.getData().then(function(res) {
angular.extend(data, res);
if (callback) {
callback(data);
}
});
return data;
}
}
})