$q.all() not running all promises before then clause - angularjs

I need to finish all my ajax calls to enable a button, but I am not getting all my promises done before enabling the button.
I have this piece of code with all my ajax gets:
$q.all([
$scope.load_ocupacoes(),
$scope.load_tipos_pisos(),
$scope.load_tipos(),
$scope.load_caracteristicas(),
$scope.load_amenidades(),
$scope.load_subtipos(true, 'incluir')
]).then(function() {
console.log('loading complete !!!');
$scope.theglyphicon = 'fa fa-check fa-fw';
$scope.isDisabledButton = false;
});
Each load function is a $http.get, like that:
$scope.load_ocupacoes = function() {
$http.get(url_api_status_ocupacao)
.success(function(response) {
console.log(response);
$scope.status_ocupacoes = response;
})
.error(function(response) {
console.log(response);
ngToast.create({
className: 'danger',
content: 'Não foi possível recuperar a lista.'
});
});
};
I have also tried this way:
$scope.load_ocupacoes = function()
{$resource(url_api_status_ocupacao).query().$promise.then(function(response) {
console.log(response);
$scope.status_ocupacoes = response;
});
};
And this... but with the same problem:
$scope.load_ocupacoes = function() {
$timeout(function(){
$scope.$apply(function() {
$scope.status_ocupacoes = appFactory.recuperarLista(url_api_status_ocupacao)
.then(function(result) {
console.log(result);
$scope.status_ocupacoes = result;
});
});
});
};
But, I am getting the message 'loading complete !!!' before the end of all loading.
Is there any problem with this approach?

There could be more errors, but the basic misunderstanding is that $q.all takes promises, and all your functions return undefined (because they don't have a return statement) - so instead of getting six promises, your $q.all gets six undefineds. AFAIK, $http.get returns a promise by default, so one way to fix it would be to just add return statement to each of your functions, in front of $http.get, like this:
$scope.load_ocupacoes = function() {
return $http.get(url_api_status_ocupacao)
.then(function(response) {
});
};

I guess $q.all accept promises.
This must be apply to all other's related method.
$scope.load_ocupacoes = function() {
$http.get(url_api_status_ocupacao)
// use then instead success
.then(function(response) {
// return raw promise instead actual value
return response;
}, console.log('error));
};

$q.all requires an array of promises but your are providing a function which is neither returning any promise.
You can do this :
$q.all([
$http.get(url_api_status_ocupacao),
$http.get(url_api1),
$http.get(url_api2)
]).then(function() {
......
});

I have resolved my problem with this approach:
var promises = [appFactory.recuperarLista(url_api_status_ocupacao),
appFactory.recuperarLista(url_api_tipos_pisos),
appFactory.recuperarLista(url_api_caracteristicas),
appFactory.recuperarLista(url_api_amenidades)
];
$q.all(promises).then(function (responses) {
$scope.status_ocupacoes = responses[0];
$scope.tipos_pisos = responses[1];
$scope.caracteristicas = responses[2];
$scope.amenidades = responses[3];
}).then(function() {
console.log('All Loading completed !!!');
});
And I made a factory returning promises:
angular.module('starter.services', ['datatables'])
.factory('appFactory', function($http, $q) {
return {
recuperarLista: function(url) {
var deferred = $q.defer();
$http({ method: "GET", url: url })
.success(function (data, status, headers, config) {
deferred.resolve(data);
}).error(function (data, status, headers, config) {
deferred.reject(status);
});
console.log('loading for ' + url + ' was completed !!!');
return deferred.promise;
}
};
});
Now I am getting this console output:
loading for api/loadliststatusocupacoes was completed !!!
services.js:171
loading for api/loadlisttipospisos was completed !!!
services.js:171
loading for api/loadlistcaracteristicas was completed !!!
services.js:171
loading for api/loadlistamenidades was completed !!!
services.js:171
All Loading completed !!!
imovel-controller.js:690

Related

Angularjs - Editing arrays returned from http get url

I have this array I am getting through the following method:
var url= *url defined here*;
$scope.ViewProfile = function () {
$http.get(url)
.success(function (response) {
$scope.ProfileList = response;
$scope.FavNumbers = $scope.ProfileList[0].FavNumbers;
})
.error(function () {
});
}
I am required to edit the Fav Numbers list on the UI. and post it back to another url through http post url method. What I am stuck is with the concept of asynchronous calls, due to which I am unable to retrieve the favorite numbers list to be available for editing. Please help!
I have tried a method of using promises as follows:
app.factory('myService', function($http) {
var myService = {
async: function(url) {
var promise = $http.get(url).then(function (response) {
console.log(response);
return response.data;
});
// Return the promise to the controller
return promise;
}
};
return myService;
});
In my controller I am doing:
angular.module('JuryApp').controller('mycontroller', ['myService', function (myService) {
myService.async(url).then(function(d) {
$scope.data = d;
});
app.controller('MainCtrl', function( myService,$scope) {
// Call the async method and then do stuff with what is returned inside our own then function
myService.async().then(function(d) {
$scope.data = d;
});
});
But I keep getting the error 'd is not defined'. It keeps giving an error of some sort, where the debugger goes into an infinite loop or something.
You are overcomplicating it, I think. Async calls are actually pretty simple:
You're service:
app.factory("myService", ["$http", function($http) {
var MyService = {
getData: function(url) {
return $http.get(url); //$http returns a promise by default
}
};
return MyService;
})];
Your controller:
angular.module('JuryApp').controller('mycontroller', ['myService', function (myService) {
$scope.FavNumbers = [];
var url = "http://my.api.com/";
myService.getData(url).then(function(response) {
$scope.FavNumbers = response.data[0].FavNumbers;
});
}]);
That's all that you need to do.

How to multi-callback a promise in AngularJs with $q?

I'm using the code below in order to simplify the backend requests but I didn't catch how to call either a success method or an error method.
How can I reach the expected behavior commented in the code?
app.factory('REST', function ($http, $q, sweetAlert) {
return {
load: function (module, action, data) {
var deferred = $q.defer();
var promise = deferred.promise;
$http
.post('/api/'+module+'.php?action='+action, data)
.success(function (data) {
if(data.error)
{
sweetAlert.swal({
title: "Error",
text: data.error,
type: "warning"
});
//HERE I WANT TO CALL .error(details)
}
else
deferred.resolve(data.result);
}).error(function () {
//HERE I WANT TO CALL .error(details)
});
promise.success = function(fn) {
promise.then(fn);
return promise;
}
return promise;
}
};
});
This is the code which uses the code above:
$scope.login = function () {
$scope.loading = true;
var payload = {'credentials': $scope.logindata};
REST.load('access', 'login', payload).success(function(data) {
if(data.redirect)
$state.go(data.redirect);
$scope.loading = false;
}).error(function(data) { //THIS SHOULD BE CALLED
$scope.loading = false;
});
}
First of all, I strongly discourage you from attaching .success to the promise you are returning. This is not Promises/A-compliant, and its subtle difference from .then (as is implemented by $http) causes a lot of confusion. Just return a pure promise.
Other than that, a few things to note:
1) you don't need another $q.defer and deferred.resolve() - just chain to the original promise of $http and return the resulting promise. (see deferred anti-pattern)
2) to reject a promise - that is, to cause the .catch (not .error - see above about the subtle difference) to fire - you should return $q.reject().
All of the above produces the following:
app.factory('REST', function($http, $q, sweetAlert){
return {
load: function(module, action, data) {
// this "return" returns the promise of $http.then
return $http.post('/api/' + module + '.php?action=' + action, data)
.then(function(response) {
var data = response.data; // .then gets a response, unlike $http.success
if (data.error) {
sweetAlert.swal({
title: "Error",
text: data.error,
type: "warning"
});
//HERE I WANT TO CALL .error(details)
return $q.reject(data.error);
}
return data.result; // what you would have "resolved"
});
}
};
})
Then, as I said above, use the .then/.catch as you would with promises:
$scope.login = function () {
$scope.loading = true;
var payload = {'credentials': $scope.logindata};
REST.load('access', 'login', payload)
.then(function(data) {
if(data.redirect)
$state.go(data.redirect);
$scope.loading = false;
})
.catch(function(error) {
$scope.loading = false;
});
}
Update yr code as below
app.factory('REST', function ($http, $q, sweetAlert) {
return {
load: function (module, action, data) {
var deferred = $q.defer();
$http.post('/api/'+module+'.php?action='+action, data)
.success(function (data) {
if(data.error)
{
sweetAlert.swal({
title: "Error",
text: data.error,
type: "warning"
});
//HERE I WANT TO CALL .error(details)
deferred.reject(data.error);
}
else{
deferred.resolve(data.result);
}
})
.error(function (error) {
//HERE I WANT TO CALL .error(details)
deferred.reject(error);
});
return defferred.promise;
}
};
});
for yr controller
$scope.login = function () {
$scope.loading = true;
var payload = {'credentials': $scope.logindata};
REST.load('access', 'login', payload).then(
function(data) {
if(data.redirect)
$state.go(data.redirect);
$scope.loading = false;
},
function(error) {
$scope.loading = false;
});
}

synchronous http call in angularJS

I have the following scenario, I need data from a particular url. I have written a function which takes parameter 'url'. Inside the function I have the $http.get method which makes a call to the url. The data is to be returned to the calling function
var getData = function (url) {
var data = "";
$http.get(url)
.success( function(response, status, headers, config) {
data = response;
})
.error(function(errResp) {
console.log("error fetching url");
});
return data;
}
The problem is as follows, $http.get is asynchronous, before the response is fetched, the function returns. Therefore the calling function gets the data as empty string. How do I force the function not to return until the data has been fetched from the url?
Take a look at promises to overcome such issues, because they are used all over the place, in angular world.
You need to use $q
var getData = function (url) {
var data = "";
var deferred = $q.defer();
$http.get(url)
.success( function(response, status, headers, config) {
deferred.resolve(response);
})
.error(function(errResp) {
deferred.reject({ message: "Really bad" });
});
return deferred.promise;
}
Here's a nice article on promises and $q
UPDATE:
FYI, $http service itself returns a promise, so $q is not necessarily required in this scenario(and hence an anti-pattern).
But do not let this be the reason to skip reading about $q and promises.
So the above code is equivalent to following:
var getData = function (url) {
var data = "";
return $http.get(url);
}
You can use $q.all() method also to solve this problem
var requestPromise = [];
var getData = function (url) {
var data = "";
var httpPromise = $http.get(url)
.success( function(response, status, headers, config) {
data = response;
})
.error(function(errResp) {
console.log("error fetching url");
});
requestPromise.push(httpPromise);
}
in the calling function
$q.all(requestPromise).then(function(data) {
//this is entered only after http.get is successful
});
make sure to inject $q as a dependency. Hope it helps
You function seems redundant. Just use $http.get(url), since you aren't really doing anything else before you use it anyway.
var url = 'foo/bar';
$http
.get(url)
.success( function(response, status, headers, config) {
$scope.data = response;
})
.error(function(errResp) {
console.log("error fetching url");
});
Or if you need to access the promise later just assign it to variable;
var promise = $http.get(url);
// some other code..
promise.then(function(data){
//.. do something with data
});
A typical way to do what you want is like so:
var getData = function(url, callback) {
$http.get(url).success(function(response) {
callback && callback(response);
});
};
Used like:
getData('/endpoint', function(data) {
console.log(data);
});

Catching Angular promise success response twice

It seems that the console output will always be:
This is the first response
This is the second response
because the success function of the inner method will be invoked first. Is this a correct assumption? Is the order guaranteed?
app.controller("ctrl", function($scope,$http) {
var getUrl = function () {
var config = {
method: 'GET',
url: 'some.txt'
};
return $http(config)
.success(function (response, status, headers, config) {
console.log('This is the first response');
})
.error(function (data, status, headers, config) {
});
};
var init = function () {
var promise = getUrl();
promise.then(
function() {
console.log('This is the second response');
});
};
init();
});
Yes, because $http return a promise itself and what you do above is promise chaining.
Although it might be better to use $http.then(success,error).then(success,error);

Factory does not execute $http.get

My factory does not seem to execute my $http.get. Here's my controller:
app.factory("myService", function($http) {
var myService = {
retrieve: function(id, type) {
var retrievedData = {
device: {},
childDevices: [],
error: {}
};
.
.
.
$http.get(url, headers)
.success(function(data, status) {
// some data post-processing
// some logs
})
.error(function(data, status) {
// some data post-processing
// some logs
});
return retrievedData;
};
return myService;
});
The logs within the $http.get do not print.
I read somewhere I need to use promise, but most examples I saw return $http.get directly. I don't want to return $http.get right away as I need to make some modification on the data in the factory rather than in the controller.
Thanks.
in angular js promise is used for returning response which come from backend. in your code retrievedData return before response come from backend. that's why angular use promise. so when response come from backend it execute success block and success block resolve the promise using deferred.resolve(data) . when error occure then error block get execute and it rejected the promise deferred.reject(err) .but when it resolve the promise it return the response data.
Service Code:
app.factory("myService", function ($http,$q) {
var myService = {
retrieve: function (id, type) {
var deferred = $q.defer();
var retrievedData = {
device: {},
childDevices: [],
error: {}
};
$http.get(url, headers).then(function (data) {
// after success this block execute
deferred.resolve(data);
},
function (err) {
//after error this block execute
deferred.reject(err);
});
return deferred.promise;
}
};
return myService;
});
controller code :
//calling retrive function
myService.retrive(id,type).then(fucntion(data){
...
})
.catch(function(){
...
})
Because when you return your retrievedData it hasn't been retrieved yet. That's why you should use promises:
app.factory("myService", function ($http,$q) {
var myService = {
retrieve: function (id, type) {
var deferred = $q.defer();
var retrievedData = {
device: {},
childDevices: [],
error: {}
};
$http.get(url, headers).then(function (data) {
// success do your success things here and return data
deferred.resolve(data);
},
function (err) {
deferred.reject(err);
});
return deferred.promise;
}
};
return myService;
});
// usage
myService.retrive(id,type).then(function(data){
// data retrived
})

Resources