Pass on value from inner get statement to out get statement - angularjs

Hi I am new to angular and wanted to understand promises. I have 2 http get (nested) one inside another. I want to use the value of the inside loop to form a link for the outside get statement as below.
$scope.loadtable = function (task){
var bgUrl = "cloudantlink";
$http.get(bgUrl)
.success(function (response) {
$scope.fileTableData =[];
for(var i =0;i<response.rows.length;i++){
var fileUrl = "cloudantURL";
$http.get(fileUrl, {responseType:'arraybuffer'})
.success(function (response) {
var file = new Blob([response], {type: 'application/pdf'});
var fileURL = URL.createObjectURL(file);
$scope.content = $sce.trustAsResourceUrl(fileURL);
console.log("this is value of promise inside loop", $scope.content);
}).error(function(data){
});
console.log("this is value of promise outside loop",$scope.content);
var fileTableEntry = {
'download' : '' + $scope.content+'',
};
$scope.TableData.push(TableEntry);
}
$scope.loadTable();
}).error(function(data){
});
};
The $scope.content value is always undefined or null outside the second loop. Could someone suggest me a way to pass the value into the first get statement.

A $http.get, or any async operation will just work in the background, and any statement you write after it won't actually wait for this to finish.
If you want to run code after it's finished, you have to use the .then method of the Promise it returns.
In this case, you probably want to wait for all these operations to finish, and then call your $scope.loadTable and related things.
To do this, save the promises returned by the requests and wait for them with $q.all to resolve. Don't forget to add $q to your controller's dependencies.
var fileRequests = [];
for(...) {
fileRequests.push($http.get(fileUrl)
.then(function success(response) { ... return fileUrl; }))
}
$q.all(fileRequests).then(function(fileUrls) { .. $scope.loadTable() })
You also overwrite $scope.content every time, I think you meant to save the URLs in $scope.fileTableData[i].
Full code:
$scope.loadtable = function (task){
var bgUrl = "cloudantlink";
$http.get(bgUrl)
.success(function (response) {
var filePromises =[];
for(var i =0;i<response.rows.length;i++){
var fileUrl = "cloudantURL";
// Saving the promises
filePromises[i] = $http.get(fileUrl, {responseType:'arraybuffer'})
.then(function success(response) {
var file = new Blob([response], {type: 'application/pdf'});
var fileURL = URL.createObjectURL(file);
// This will be the result when the promise is resolved
return $sce.trustAsResourceUrl(fileURL);
}, function error(data) {
});
}
// Waiting for the promises
$q.all(filePromises).then(function(fileUrls)
{
// fileUrls contain the results returned by the success callback
$scope.TableData = fileUrls.map(function(url) {
return { 'download' : '' + url+'', };
})
$scope.loadTable();
})
}).error(function(data){
});

Related

Print message after last ajax call in AngularJS

I am trying to make few ajax call inside a loop. I want to print a message only when my last ajax is successful. Any suggestions what I am doing wrong here.
$scope.defer = $q.defer();
$scope.promises = [];
$scope.array = [1,2,3,4,5,6,7,8,9,10];
$scope.makecall = function(){
angular.forEach($scope.array, function(index){
$timeout(function() {
var promise = $http({
url : 'https://jsonplaceholder.typicode.com',
method: 'GET',
}).
success(function(data){
});
$scope.promises.push(promise);
}, index * 2000);
});
return $scope.defer.promise;
}
$scope.makecall();
$q.all($scope.promises).then(function(){
console.log('over!');
});
I think you can check the SO
Wait for all promises to resolve
$q.all([one.promise, two.promise, three.promise]).then(function() {
console.log("ALL INITIAL PROMISES RESOLVED");
});
var onechain = one.promise.then(success).then(success),
twochain = two.promise.then(success),
threechain = three.promise.then(success).then(success).then(success);
$q.all([onechain, twochain, threechain]).then(function() {
console.log("ALL PROMISES RESOLVED");
});
you may also check
function outerFunction() {
var defer = $q.defer();
var promises = [];
function lastTask(){
writeSome('finish').then( function(){
defer.resolve();
});
}
angular.forEach( $scope.testArray, function(value){
promises.push(writeSome(value));
});
$q.all(promises).then(lastTask);
return defer.promise;
}

$http.post in angularJS goes in error in without debugging mode only.in debugging mode its works fine.why?

here is my javascript code
$scope.addUser = function () {
debugger;
url = baseURL + "AddUser";
$scope.objUser = [];
$scope.objUser.push( {
"ID": '0',
"UserName": $scope.txtUserName,
"Password": $scope.txtPassword,
"Role":"Non-Admin"
});
$http.post(url,$scope.objUser[0])
.success(function (data) {
debugger;
alert("S");
window.location = "../View/Login.html";
}).error(function () {
debugger;
alert("e");
});
}
here is my server method code
[HttpPost]
public int AddUser(UserModel user)
{
//_entity.Configuration.ProxyCreationEnabled = false;
tblUser objUser = new tblUser();
objUser.UserName = user.UserName;
objUser.Password = user.Password;
objUser.Role = user.Role;
_entity.tblUsers.Add(objUser);
_entity.SaveChanges();
return objUser.ID;
}
You can use promises to get the response. this can be inside into a service and call it whenever you want to use it.
this.addUser = function (obj) {
var datosRecu = null;
var deferred = $q.defer();
var uri = baseUrl + 'addUser';
$http({
url: uri,
method: 'post',
data: angular.toJson(obj)
}).then(function successCallback(response) {
datosRecu = response;
deferred.resolve(datosRecu);
}, function errorCallback(response) {
datosRecu = response;
deferred.resolve(datosRecu);
});
return deferred.promise;
};
Also .error and .success are deprecated.
PD: the parameter data: inside the $http correspond to the body. if you want to send parameters you should use params:{}
EDIT:
Here i leave you a link how promises work. Angular promises
Basically this helps to process data asynchronously
the example above can be used inside a service like this
myApp.service('myService', function($q, $http){
// here your services....
});
the service can be injected inside to any controller to provide the data that what you want, inside of your functions
myApp.controller('myController', function($scope, myService){
$scope.list = function(){
$promise = myService.getAll(); // this will be the name of your function inside your servive
$promise.then(function(data){
console.log(data); //here you can se your promise with data like status and messages from the server.
});
};
});
Hope it helps.

AngularJS Service with multiple, depending queries

I'm trying to create an AngularJS service, which returns data based on several HTTP requests. But i seem to just not get it to work.
The REST call works as follow:
get /index which returns an array of urls
call each of the url's, and add the result to an array
I expect that at the end of the call of the service function, that i receive a data structure containing all the data from the url's.
My current, somewhat working code uses callbacks, but even though it works in one controller, it does not in another. I want to correctly use promises, but i'm already confused with success vs then.
My service:
// Get a image
obj.getByUrl = function (imageUrl, callback) {
$http.get('https://localhost:9000' + imageUrl).success(function (data) {
callback(data);
});
}
// Get all images
obj.getAll = function(callback) {
$http.get('https://localhost:9000/1.0/images').success(function (data) {
if (data.status != "Success") {
console.log("Err");
}
var images = [];
for(var n=0; n < data.metadata.length; n++) {
var c = data.metadata[n];
obj.getByUrl(c, function(data2) {
images.push(data2.metadata);
});
}
callback(images);
});
}
i'd like to use the service in a controller resolve like this:
resolve : {
images: function(ImagesServices, $route) {
return ImagesServices.getState($route.current.params.containerName)
},
I came as far as this, but it does only return the data of the index call, not the aggregated data:
obj.getAll3 = function() {
var images = [];
var promises = [];
//var httpPromise = $http.get('https://localhost:9000/1.0/images');
var httpPromise = $http({
url: 'https://localhost:9000/1.0/images',
method: 'GET',
});
return httpPromise.success(function(data) {
var data2 = data.metadata[0];
// angular.forEach(data.metadata, function(data2) {
console.log("D11: " + JSON.stringify(data2));
//var inPromise = $http.get('https://localhost:9000' + data2)
var inPromise = $http({
url: 'https://localhost:9000' + data2,
method: 'GET',
})
.success(function (data2) {
console.log("D2: " + JSON.stringify(data2));
images.push(data2);
});
promises.push(inPromise);
// });
return $q.all(promises).then(function() {
return images;
});
});
}
Maybe someone can point me into the right direction?
This is the typical case where chaining promises, and using $q.all(), is adequate:
/**
* returns a promise of array of images
*/
obj.getAll = function() {
// start by executing the first request
return $http.get('https://localhost:9000/1.0/images').then(function(response) {
// transform the response into a promise of images
// if that's not possible, return a rejected promise
if (data.status != "Success") {
return $q.reject("Error");
}
// otherwise, transform the metadata array into
// an array of promises of image
var promises = data.metadata.map(function(imageUrl) {
return $http.get('https://localhost:9000' + imageUrl).then(function(resp) {
return resp.data;
});
});
// and transform this array of promises into a promise
// of array of images
return $q.all(promises);
});
}
This avoid the callback antipattern, and uses chaining. It's a bit long to explain here, but I wrote a blog post that should, hopefully, make the above code clear: http://blog.ninja-squad.com/2015/05/28/angularjs-promises/

ng-csv with data from api calls

I need to assign data to ng-csv from api call.
I tried this. but didn't worked
script:
$scope.getArray = function () {
var temp;
$http.get(Config.serviceUrlBase + '/abc/ExportToCSV').success(function(data, status, headers, config) {
temp = data;
})
return temp;
};
//here data is string separated by comma and new line for csv format.
aspx file:
<Button ID="ExportToCSV" ng-csv="getArray" filename="test.csv" lazy-load="true"
>ExportToCSV</Button>
Am I missing anything?
The temp variable is assigned to asynchronously, which means that return temp; actually returns undefined.
The ng-csv attribute accepts promises, so you should use $q:
$scope.getArray = function () {
var deferred = $q.defer();
$http
.get(Config.serviceUrlBase + '/abc/ExportToCSV')
.success(function(data, status, headers, config) {
deferred.resolve(data);
});
return deferred.promise;
};
Note: $q is a service that you can inject in your controller or wherever it is you can inject things.
You are missing '()'.
ng-csv="getArray()"
I have the same issue and it's solved by the following:
$scope.getArray = function () {
var temp = $http.get(Config.serviceUrlBase + '/abc/ExportToCSV').success(function(data, status, headers, config) {
return data;
})
return temp;
};
The issue was because temp variable by default is undefined. So, You should wait till the variable has returned value from promise.
To solve this you need to use a promise with your lazy load, but you must also include the resolved response as an array as your data is in JSON format.
Leaving the response in JSON format led to 0 being loaded only under the first column when we had a collection being returned.
In the below AngularJS example we had a collection we wanted to store in the array (i.e. rows of data):
$scope.getArray = function() {
var deferme = $q.defer();
$http.get(url).success(function(data) {
var myArr = [];
for(var i=0; i < data.length; i++) {
myArr.push([data[i].value1, data[i].value2, etc...]);
}
deferme.resolve(myArr);
});
return deferme.promise;
}
the value of the ng-csv directive should be an expression, a value or a promise.
So you can assign $scope.getArray
myapp.controller('myctrl', function ($scope) {
$http.get(url)
.success(function (data) {
$scope.getArray = data;
});
});
AngularJS is watching for scope variable to be updated.

How can I have two promise called in a Angular service and return combined data

I am having a service which is calling two other async services and returns some combined data, but how can this be done in AngularJS.
I have a controller in which I would like to call these two methods similar to this:
function ServiceC(serviceA,serviceB) {
var dataA = serviceA.GetAsyncStuff(); //returns promise
var dataB = serviceB.GetAsyncStuff(); //returns promise
return 'Greetings ' + dataA + dataB;
}
Is there a smarter way than to actually nest the Then method calls like this:
function ServiceC(serviceA,serviceB) {
var dataA = serviceA.GetAsyncStuff().then(function(respA){
var dataB = serviceB.GetAsyncStuff().then(function(respB){
return 'Greetings ' + respA.data + respB.data;
});
});
}
This example is of course a bit simplified.
Here is a demo plunker: http://plnkr.co/edit/yCrbwnarVDqwC4GBxhGg?p=preview
You need to use $q.all:
app.factory('myService', function($q, serviceA, serviceB, serviceC){
// $http returns a response object so we need to extract the data
var fn = function(res){
return res.data;
};
var promises = [
serviceA.GetAsyncStuff().then(fn),
serviceB.GetAsyncStuff().then(fn)
];
return $q.all(promises).then(function(data){
// you can manipulate consolidated data here
// data.push(serviceC);
return data;
});
});
From $q docs:
$q#all(promises);
Combines multiple promises into a single promise that is resolved when all of the input promises are resolved.
Returns
Returns a single promise that will be resolved with an array/hash of values, each value corresponding to the promise at the same index/key in the promises array/hash. If any of the promises is resolved with a rejection, this resulting promise will be rejected with the same rejection value.
function ServiceC(serviceA,serviceB) {
var _totalData = {};
var dataA = serviceA.GetAsyncStuff().then(function(respA){
_totalData = respA;
});
var dataB = serviceB.GetAsyncStuff().then(function(respB){
_totalData += respB;
});
return{ totalData: _totalData}
}
I say first one is better as it is having two different calls and you can add your data and return it at the end and and in your second example you using service under service that would creating a overhead for saving the value of one service till 2nd service get called and call its data, you can see the network pressure second one is taking much time to get the resources and to return the resources.
We can call both services and return promise.
myApp.provider("myService", function($http,$q){
var serviceOneData = {},
serviceTwoData = {};
//call service 1
return {
serviceOneData : serviceOneData ,
serviceTwoData : serviceTwoData ,
getService1: function(){
var deferred = $q.defer();
$http({method: 'GET',url:'Service1',
headers:{
'Access-Control-Allow-Origin': '*'}}).
success(function(data,status,header,config){
serviceOneData = data;
deferred.resolve();
})
.error(function (data,status,header,config) {
deferred.reject();
});
//call service 2
return deferred.promise;
},
getService2: function(){
var Seconddeferred = $q.defer();
$http({method: 'GET',url:'Service2',
headers:{
'Access-Control-Allow-Origin': '*'}}).
success(function(data,status,header,config){
serviceTwoData = data;
Seconddeferred.resolve();
})
.error(function (data,status,header,config) {
Seconddeferred.reject();
});
//call service 2
return Seconddeferred.promise;
},
getService : getService1().then(getService2()).
then(
return serviceOneData + serviceTwoData
);
}
} );
You can chaining promise:
angular.module('app',[])
.factory('Service1',function($q,$timeout){
return {
f: function(){
var deferred = $q.defer();
$timeout(function() {
deferred.resolve('Service 1');
},1000);
return deferred.promise;
}
}
})
.factory('Service2',function($q,$timeout,Service1){
return {
f: function(){
var deferred = $q.defer();
Service1.f().then(function(data){
$timeout(function() {
deferred.resolve('Service 2 '+ data);
},1000);
});
return deferred.promise;
}
}
})
.controller('MainCtrl', function($scope,Service2){
var promise2 = Service2.f();
promise2.then(function(data2){
console.log(data2);
});
});
or just use
$q.all([Service1,Service2]).then
http://denisonluz.com/blog/index.php/2013/10/06/angularjs-returning-multiple-promises-at-once-with-q-all/
Your best bet is to use $q.all, which makes sure that all of the requested promises have been resolved before attempting to execute a function
function ServiceC(serviceA, serviceB, $q) {
var dataA = serviceA.GetAsyncStuff(); //returns promise
var dataB = serviceB.GetAsyncStuff(); //returns promise
$q.all([dataA, dataB]).then(doSomething);
}
EDIT: If you need to return the data, you're going to have to return a promise. You can either just return $q.all or resolve a new promise once $q.all has been resolved, e.g.
function ServiceC(serviceA, serviceB, $q) {
var dataA = serviceA.GetAsyncStuff(); //returns promise
var dataB = serviceB.GetAsyncStuff(); //returns promise
var deferred = $q.defer();
$q.all([dataA, dataB]).then(function (promises) {
deferred.resolve('Greetings ' + promises[0] + promises[1]);
});
return deferred.promise;
}

Resources