promise not working on REST call in service in angularJs - javascript

I have a REST call in service layer on which I have defined a promise which is making this asynchronous call a synchronous one and I am calling it from my controller method. Below is the code:
service method:
app.lazyload.factory('myService',['$http','$q', function($http,$q) {
return{
showAll :function ()
{
var deferred = $q.defer();
$http.post('rest/getAll?cd='+ (new Date()).getTime())
.success(function(data)
{
deferred.resolve(data);
})
.error(function(data)
{
deferred.reject(null);
console.log("in error block");
});
return deferred.promise;
}
};
}]);
controller method:
$scope.showAll = function()
{
var promise = myService.showAll();
promise.then(function success(data) {
$scope.allitems = data;
console.log(data);
console.log('$scope.allitems'+$scope.allitems[0].name);
$scope.showAllitems = true;
blockMyUI();
}, function error(msg) {
console.error(msg);
});
};
While debugging this javascript if I halt it for 2 sec i get the response but i don't get it if done non-stop. This means all REST call are working fine but there is some problem in my 'promise'. This promise is not waiting for REST call to complete which I want.

Try using $watch in controller.
var dataFromFactory = '';
myService.showAll().then( function(data){
dataFromFactory = data;
}
$scope.$watch(function () {
return dataFromFactory;
},
function (val) {
$scope.allitems = val;
console.log(val);
//the rest value you want.
}, false);

Related

Issue with AngularJS promises within a factory

I have an angularjs factory like this:
'use strict';
angular.module('frontRplApp')
.factory('paymentService', function ($rootScope, $http, config, tools) {
var urlBase = config.baseUrl;
var paymentService = {
response: {},
create: function () {
var args = {};
return $http.post(urlBase + 'api/investor/payment/create', args);
}
});
And I intend to use it inside a controller like this (the important issue is being to do something different if all went well or if there was an error)
$scope.order = function () {
console.log('PaymentCashCtrl.order');
$scope.disabledButtons.submitCashOrder = true;
paymentService.create()
.then(
function (response) {
// do something with response
}, function (error) {
// do something with an error
}));
};
However my issue is that Id like to update some of the paymentService fields as the response of the $http.post is resolved and then return the promise so that the function(response) and function(error) callbacks in the controller keep working.
I tried with something like:
return $http.post(urlBase + 'api/investor/payment/create', args)
.then(function(response){
console.log(response);
this.response = response;
return response;
});
But it doesnt work since the function(error) handler in the controller is never called.
I want to use my handlers in the controller but also make some updates when the $http.post response is resolved.
Thanks.
in the factory, you need to return the functions paymentService object. also, don't resolve the promise inside the factory. resolve it in the controller.
.factory('paymentService', function($rootScope, $http, config, tools) {
var urlBase = config.baseUrl;
var paymentService = {
response: {},
create: function() {
var args = {};
return $http.post(urlBase + 'api/investor/payment/create', args);
}
}
return paymentService;
});
$scope.order = function() {
console.log('PaymentCashCtrl.order');
$scope.disabledButtons.submitCashOrder = true;
paymentService.create()
.then(
function(response) {
// do something with response
},
function(error) {
// do something with an error
}));
};
Use $q
Change your factory code to this:
angular.module('frontRplApp')
.factory('paymentService', function ($rootScope, $http, config, tools, $q) {
var urlBase = config.baseUrl;
var paymentService = {
response: {},
create: function () {
var deferred = $q.defer();
var args = {};
$http.post(urlBase + 'api/investor/payment/create', args)
.then(function(response){
console.log(response);
paymentService.response = response;
deferred.resolve(response);
}, function (error) {
deferred.reject(error);
});
return deferred.promise;
}
};
return paymentService;
});

One time call http request using angularjs

function get (id, ignore) {
var deferred = $q.defer();
$http.get('v1/info/' + id, {
ignoreAuthModule: ignore
})
.success(function (data) {
deferred.resolve(data.data);
})
.error(function (reason) {
deferred.reject(reason.message););
});
return deferred.promise;
}
init();
function init(){
users.get($routeParams.id)
.then(function (data) {
if(data.has_something === 1){
$scope.hasSomething = true;
}else{
$scope.hasSomething = false;
}
});
}
I have a Service that get the information about user using promise and Fetching information from the service with init function
//if i call init function this should call two times one from function initialization and other i'm calling it from service
how can i stop two times calling api I mean it should call one time if already called
You're using the explicit promise creation antipattern here, and your code could be much simpler. Here is how you can use memoization to avoid requesting the same user twice:
.factory('users', ['$http', function ($http) {
var userPromises = {};
function get (id, ignore) {
if (!userPromises[id]) {
userPromises[id] = $http.get('v1/info/' + id, {
ignoreAuthModule: ignore
})
.then(function (data) {
return data.data;
})
.catch(function (reason) {
throw new Error(reason.message);
});
}
return userPromises[id];
}
return {
get: get
};
});
You can assign your deferred.promise to some variable and then return that variable, and before your http call just check whether that variable is already defined or not
function get (id, ignore) {
if (angular.isUndefined(user)) {
var deferred = $q.defer();
$http.get('v1/info/' + id, {
ignoreAuthModule: ignore
}).then(function(response) {
if (response.status == 200) {
deferred.resolve(response.data);
} else {
deferred.reject(response.data);
};
user = deferred.promise;
return user;
} else {
return user;
}
}
This way your api will get called only once.

Use output from services to controllers

I want to result of my $http.get from my service to my controller.
myserviceSample.js
function messagesService($q,$http){
var messages;
$http({
method: 'GET',
url: 'http://api.com/feedback/list'
})
.then(function success(response){
messages = response.data;
console.log(messages);
},function error(response){
console.log('error'+ response);
});
console.log(messages);
return {
loadAllItems : function() {
return $q.when(messages);
}
};
}
})();
mycontrollerSample.js
function MessagesController(messagesService) {
var vm = this;
vm.messages = [];
messagesService
.loadAllItems()
.then(function(messages) {
console.log(messages);
vm.messages = [].concat(messages);
});
}
})();
The above code results gives undefined output.
What i miss?
$q.when object does expect promise/object to make it working. In your case you have to pass promise object to $q.when as you are doing $http.get call. Here messages object doesn't hold promise of $http.get, so you could change the implementation of method like below.
Service
function messagesService($q,$http){
var messages = $http({
method: 'GET',
url: 'http://api.com/feedback/list'
})
.then(function success(response){
return response.data;
},function error(response){
return $q.reject('Error Occured.');
});
return {
loadAllItems : function() {
return $q.when(messages);
}
};
}
Then controller will resolve that promise & .then will do the trick
function MessagesController(messagesService) {
var vm = this;
vm.messages = [];
messagesService
.loadAllItems()
.then(function(messages) {
console.log(messages);
vm.messages = [].concat(messages);
});
}
Note: Using $q to create a custom promise, is considered as bad pattern when you have $http.get method there(which does return
promise itself)
Improved Implementation
function messagesService($q, $http) {
var messages, getList = function() {
return $http({
method: 'GET',
url: 'http://api.com/feedback/list'
})
.then(function success(response) {
messages = response.data
return response.data;
}, function error(response) {
return $q.reject('Error Occured.');
});
};
return {
loadAllItems: function() {
if (!data)
return getList(); //return promise
else
return $q.resolve(messages); //return data
}
};
};

Angularjs $http delete with $q promise leads to TypeError: object is not a function

The following snippet returns the following error: TypeError: object is not a function
service.deleteItem = function(itemId) {
var def = $q.defer();
$http.delete(SERVER_REST_PATH + '/items/' + itemId)
.success(function() {
def.resolve();
}).error(function(data, status) {
def.reject("Error deleting the item");
});
return def.promise();
};
If I rewrite it as the following it works:
service.deleteItem = function(itemId) {
return $http.delete(SERVER_REST_PATH + '/items/' + itemId);
};
All other $http methods that I use(i.e GET, PUT, POST) in my app are wrapped with the $q the same way and they don't have this issue. Only the DELETE is causing this issue. When I debug it it just skips the $http's success(), error() and then() methods. I'm using angular version 1.3.13.
change return def.promise(); to return def.promise;
example :
function deferredTimer(success) {
var deferred = $q.defer();
$timeout(function() {
if (success) {
deferred.resolve({ message: "This is great!" });
} else {
deferred.reject({ message: "Really bad" });
}
}, 1000);
return deferred.promise;
}

Angular $http returns data but doesn't apply to scope

In angular, I have this factory
.factory('Users', function($http) {
var users = [];
return {
getUsers: function() {
return $http.get("data.json")
.then(function(response) {
users = response.data;
return users;
});
},
getUser: function(id) {
for (i = 0; i < users.length; i++) {
if (users[i].id == id) {
return users[i];
}
}
return null;
}
}
})
And then load that data in my controller
.controller('SessionsCtrl', function($scope, Users) {
$scope.users = Users.getUsers();
})
If I console.log the response from the http request, I am getting the data, but for some reason, the scope data won't update.
I've seen examples where the controller would look like this
Users.getUsers().then(function(data) {
$scope.users = data;
});
but from my understanding, I shouldn't need to since $http is already returning a promise. Am I missing something? Do I need to involve $q at all?
This will work:
getUsers: function() {
return $http.get("data.json");
},
and:
Users.getUsers().then(function(data) {
$scope.users = data.data;
});
What you wrote however will not work, simply because you can't directly return a result from an operation that will complete later such as a $http call.
The problem with this:
getUsers: function() {
return $http.get("data.json")
.then(function(response) {
users = response.data;
return users;
});
},
Is that by the time the return users; line executes the ajax call is still in progress and nothing has been returned yet, so you will get nothing for users. For what you're looking to do I would go about using a callback:
getUsers: function(callback) {
$http.get("data.json")
.then(function(response) {
users = response.data;
callback(users);
});
},
Usage:
Users.getUsers(function(data) {
$scope.users = data;
});
Your getUsers function is still returning a promise because its returning the value of $http.get. So, yes, the value you're assigning to $scope.users is a promise. You'll have to handle the promise to set the value to $scope.users according to your example above:
Users.getUsers().then(function(data) {
$scope.users = data;
});

Categories

Resources