AngularJS : Restangular Library - javascript

I am experimenting with the fabulous Restangular library, and I have run into some trouble when trying to return some JSON objects and bind them to the $scope object.
I have this function inside my Factory script, which essentially is just returning a list of blogs utilising the Restangular.getList() function.
angular.module("ecmaworld").factory("Authenticate", function(Restangular) {
// Testing Function
var Blogs = Restangular.all("blogs");
return {
blogs: function() {
Blogs.getList("blogs").then(function(blogs) {
return blogs;
}, function(error) {
console.log(error);
});
}
};});
The Factory method here returns the a list of blog posts. I then attempt to call this function which I ahve defined in the Factory script and utilise it in one of my controller scripts like this:
angular.module("ecmaworld").controller("LoginController", function($scope, Authenticate) {
//Testing function
$scope.getBlogs = function() {
$scope.blogs = Authenticate.blogs();
};
});
When I attempt to use the "data-ng-repeat" directive to loop through all the blogs posts, I do not get anything displaying. I can see that teh API method has worked through google developers as the http response returns the JSON objects. However, I am unsure to why they are not displaying when attempting to loop through them in the VIEW. If you could please assist me, that would be much appreciated. I am only new to Angular, so go easy guys.
Thanks.

The blogs() method needs to return the promise...
blogs: function() {
return Blogs.getList("blogs").then(function(blogs) {
return blogs;
}, function(error) {
console.log(error);
});
}
And then assign the result to the scope property when the promise is resolved...
$scope.getBlogs = function() {
Authenticate.blogs().then(function (blogs) {
$scope.blogs = blogs;
});
};

Related

Cannot read property 'then' of undefined with nested function calls

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.

angular promise and $http

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);
});
});

Getting empty return result in $http.get() in AngularJS 1.5.0

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.

How to access async data in a factory across multiple controllers without using promises

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;
}
}
})

AngularJS : Access stored data in a factory after a $http call

I am trying to build a factory to act as a staging area for my database models, as well as an api to perform basic CRUD calls. I want to be able to access data by storing it in a service or a factory, and keep api methods along with it so I can perform actions like these in the controller.
$scope.folders = Folders.data(); // for a factory
$scope.folders = Folders.data; // for a Service
Folders.create({name: "My Stuff, $oid: { 5fwewe033333 }, user_id: CurrentUser.id"});
Currently I am using the Folder factory like this in the controller.
Folders.foldersData().success( function(data, status) {
$scope.folder = data;
})
.error( function(data,status) {
Flash.warning("There was a problem fetching your data");
});
I know I can just have a promise resolved in the controller, but with the size of the project I'm working on, I like the idea of accessing the Folders model in a service, with out having to make a server call to sync the data every time I make a change.
angular.module('cmsApp')
.factory('Folders', function($http, $q){
var folders = {};
var messageWarn = "Upload Retrival Failed.";
return {
get: function(){
var defered = $q.defer();
$http.get('/folders').success( function ( data, status ) {
defered.resolve(data);
})
.error( function ( data, status ) {
defered.reject();
Flash.warning(message_warn);
});
defered.promise.then( function (promise)
folders = promise;
});
},
data: function (){
return folders;
},
}
});
My problem is that I can't keep the folders object to persist after I call Folders.get(). It always comes back after I call Folders.data() as an empty object.
Is there a way to keep this data stored in the Factory as a up-to-date representation of the Folder model that is not dependent on hitting the server every time?
Running angular 1.2.3, on a Rails 4 API.
You can store the promise in the service as an object on the service. I forked the expanded demo above to demonstrate http://plnkr.co/edit/2HqQAiD33myyfVP4DWg3?p=preview
As with the previous examples, the http call is only made once but this time the promise is added to the folders item on the service object which gets created by the factory.
app.factory('myService', function($http, $q) {
return {
myObject: '',
get: function() {
// Create the deffered object
var deferred = $q.defer();
if(!this.myObject) {
// Request has not been made, so make it
$http.get('my-file.json').then(function(resp) {
console.log('Making the call!');
deferred.resolve(resp.data);
});
// Add the promise to myObject
this.myObject = deferred.promise;
}
// Return the myObject stored on the service
return this.myObject;
}
};
});
In this example, the service essentially IS the data. The first time the service is injected, a promise is created and the call goes out. The service is actually the promise of that data, but when the call comes back, the promise is resolved with the data. So, the second, third, etc time the service is injected, the call isn't made again - the factory has already done its job and returned the service (the promise in this example).
Live demo (click).
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, myService) {
myService.then(function(data) {
$scope.data = data
})
});
app.factory('myService', function($http, $q) {
//this runs the first time the service is injected
//this creates the service
var promise = $http.get('my-file.json').then(function(resp) {
return resp.data;
});
return promise;
});
Here's an expanded demo in which I use the data twice. Note the console log - the call is only ever made once. In this demo, I made the service into an object with a get method that returns the promise. I just wanted to demonstrate another way this technique could be implemented.
app.factory('myService', function($http, $q) {
console.log('Making the call!');
var promise = $http.get('my-file.json').then(function(resp) {
return resp.data;
});
var myService = {
get: function() {
return promise;
}
};
return myService;
});

Categories