Iterating inside $http.get - angularjs

I've this block of code which displays 20 items per request.
.controller('MovieController',function ($scope,$http) {
$scope.movies = $http.get(https://api.themoviedb.org/3/movie/popular&page=1)
.then(
function (response) {
$scope.movies = response.data.results;
}
);
})
Instead of page=1, if i put page=2, I'll get another set of 20 items and so on. How to iterate inside the $http.get if I want more than 1 get request in a single page? I want to display the 2nd 20 items after displaying the 1st 20.

There is the classic way of chaining callback functions together to achieve the desired result. Or there is the better way, which uses $q.all().You should use $q.all to send multiple http requests at once
var reqAr = [];
for (var i = 0; i <= 1; i++) {
reqAr.push($http.get("https://api.themoviedb.org/3/movie/popular&page=" + i))
}
$q.all(reqAr).then(function(response) {
console.log(response[0].data) //page 1 content
console.log(response[1].data) //page 2 content
for(var j = 0; j < response.length; j++) {
$scope.movies = $scope.movies.concat(response[j].data.results);
}
})

Related

Loading of paginated data from API

I am working on a system that currently requires me to load all items from an API.
The API is built with pagination feature in it. I keep calling the API a number of times and $http.get cursing the system not to respond. For example, once I load the page that needs to call the API many times (like 50 to 80 times depending on the number of pages), for a few minutes anything I do won't respond until the calling of the API is almost finished. I already tried a lot of ways but it won't work.
$scope.loadAllPagedItems = function (category_uuid, max_pageitem, item_perpage) {
for (var a = 0 ; a < max_pageitem; a++) {
itemResource.findItems(category_uuid, item_perpage, a).then(function (response) {
if (response.data.data.length > 0) {
for (var a = 2 ; a < $scope.categories.length; a++) {
if ($scope.categories[a][0].category_uuid == response.data.data[0].category_uuid) {
for (var j = 0; j < response.data.data.length; j++) {
$scope.categories[a][0].data.push(response.data.data[j]);
}
}
}
}
}, function (error) {
console.log(error);
})
}
}
Is there any way I can do this better?
Sequentially Retrieving Paginated Data from an Asynchronous API
$scope.loadAllPagedItems = function(category_uuid, max_pageitem, item_perpage) {
var promise = $q.when([]);
for (let a = 0 ; a < max_pageitem; a++) {
promise = promise
.then(function(dataArray) {
var p = itemResource.findItems(category_uuid, item_perpage, a);
p = p.then(function (response) {
return dataArray.concat(response.data.data);
});
return p;
});
};
return promise;
};
The above example, executes XHRs sequentially and uses the array concat method to merge the resolved arrays into a single array.
Usage:
$scope.loadAllPagedItems(category, pages, itemsPerPages)
.then(function(finalArray) {
console.log(finalArray);
}).catch(function(response) {
console.log("ERROR ",response.status);
throw response;
});

iterating inside a $http.get

I've this block of code which displays 20 items per request.
.controller('ActorController',function($scope,$http) {
$scope.getActors = function () {
var actors = $http.get(https://api.themoviedb.org/3/person/popular&page=1);
actors.then(
function (response) {
$scope.actors = response.data.results;
}
);
}
})
Instead of page=1, if i put page=2, I'll get another set of 20 items and so on. How to iterate inside the $http.get if I want more than 1 get request in a single page? I want to display the 2nd 20 items after displaying the 1st 20.
So you're saying that you want to make multiple calls to $http.get in a loop? If so you'd do something like this:
.controller('ActorController',function($scope,$http) {
$scope.getActors = function () {
for(var i = 0; i < 5; i++) {
getPage(i);
}
}
function getPage(i) {
var actors = $http.get('https://api.themoviedb.org/3/person/popular&page=' + i);
actors.then(function (response) {
for(var j = 0; j < response.data.results.length; j++) {
$scope.actors.push(response.data.results[j]);
}
});
}
})
That will put the data for the first 5 pages into the $scope.actors array.
you can use $q.all to send multiple http requests at once
var fulAr = [];
for (var i = 1; i <= 2; i++) {
fulAr.push($http.get("https://api.themoviedb.org/3/person/popular&page=" + i))
}
$q.all(fulAr).then(function(response) {
console.log(response[0].data) //page 1 content
console.log(response[1].data) //page 2 content
for(var j = 0; j < response.length; j++) {
$scope.actors = $scope.actors.concat(response[j].data.results);
}
})
Make sure to inject $q to controller

$http in loop, wait the results

I have this :
var j = 0;
// myList.length = 3
while(j < self.myList.length - 1){
$http.post('myURL', self.myList[j].code).then(
function(response){
self.myList[j].plop = response.data;
}, function(){
// error
}
).then(
function(){
// with this j++, my web page is freezing
// j++;
}
);
// with this j++, only the 3rd element of myList have a "plop" element
//j++;
}
My problem is in comments :) for "j++".
If I remove the loop while and hardcoded the 3 step, it's working. But I don't know how to solve the issue with a loop. Do you have an idea ? Thanks
Synchronized solution according to OP's comment:
var promises = [];
for(var i=0;i<self.myList.length;i++)
promises.push($http.post(...));
$q.all(promises).then(function(results){
//All results available here
var data = results.map(result => result.data);
data.forEach((e, idx) => self.myList[idx] = e);
})
.catch(function(e){
//Handle error
});
Issue is
$http.post().then(function(){}, function(){}) is asynchronous function. So .then() method will be executed when loop is completed. This is the reason it always takes last value of j that is 2.
then() will come only one time with $http.post() so remove second .then()
Solution posted below:
var j = 0;
var i = 0;
// myList.length = 3
while(j < self.myList.length - 1){
$http.post('myURL', self.myList[j].code).then(function(response){
self.myList[i].plop = response.data;
i++;
}, function(){
// error
}
);
}

Angular sequential $http requests of multiple elements in list?

Say I have a list:
var mylist = ["a","b","c","d"];
I want to request data for each one of these like so and get the responses back in the same order.
var comeback = [];
getMyData()
function getMyData() {
for (int i = 0; i < mylist.length; i++) {
$http.get("http://myurl/" + mylist[i]).success(function(data) {
results.append(data);
});
}
}
How can I make sure that the "comeback" list has all the responses based on "a", "b", etc. in the same order? What is the best way to write this?
Chaining the promises will make them execute in series. Something like:
var results = [];
getMyData(0);
function getMyData(i) {
return $http.get("http://myurl/" + mylist[i]).success(function(data) {
results.push(data);
i++;
if(i < mylist.length) {
getMyData(i);
}
});
}
Note: If you want to do more advanced validation and error checking, you would need to use $q.

How to do paginated API calls until reaching the end?

I imagine this could be a pretty general problem, but in this case I'm using AngularJS and the SoundCloud API.
Here's the flow:
Call loadTracks()
loadTracks() should load the tracks of a SoundCloud user, 50 at a time, until the list runs out.
loadTracks() does this by calling another function, sc.getTracksByUser(id), which returns a promise
loadTracks() should update the variable $scope.tracks with each 50 track batch when it arrives
The SoundCloud API provides an option offset, so loading the batches is relatively easy. I think it's the promise that is tripping me up. Without the promise, the solution would be:
$scope.tracks = [];
var loadTracks = function() {
var page = -1,
done = false,
newTracks;
while (!done) {
newTracks = getFiftyTracks(page++);
for (var i = 0; i < newTracks.length; i++) {
$scope.tracks.push(newTracks[i]);
}
if (newTracks.length < 50) done = true;
}
}
Unfortunately, that line with getFiftyTracks in it is not how it works. The actual implementation (using a promise) is:
sc.getTracksByUser(id).then(function (response) {
for (var i = 0; i < response.length; i++) {
$scope.tracks.push(response[i]);
}
}
I'm guessing the solution to this is some sort of recursion, but I'm not sure.
You can do that in this way
sc.getTracksByUser(id).then(function (response) {
for (var i = 0; i < response.length; i++) {
$scope.tracks.push(response[i]);
}
// if response return 50 track call getTracksByUser again
if (response.length === 50) sc.getTracksByUser(id);
});

Resources