I' using JSzip to create zipfile which contain all the images files. I got the images from external links within a loop using XMLHttpRequest. According to my code zipfile create before complete the XMLHttpRequest. So it returns empty zip file. How to create zip file after looping all the files?
$(document).on('click', '.download', function(){
var path = $(this).attr("data-id");
var count = $(this).attr("value");
var storageRef = firebase.storage().ref();
var zip = new JSZip();
console.log(count);
for (i = 1; i <= count; i++) {
console.log(path+i+".png");
var imagePath = path+i+".png";
// Create a reference to the file we want to download
var starsRef = storageRef.child(imagePath);
starsRef.getDownloadURL().then(function(url) {
// Insert url into an <img> tag to "download"
ImageUrl = url;
var xhr = new XMLHttpRequest();
xhr.open('GET', ImageUrl, true);
xhr.responseType = "arraybuffer";
xhr.onreadystatechange = function(evt) {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
zip.file(i+".png", xhr.response);
}
}
};
xhr.send();
})
}
zip.generateAsync({type:"blob"})
.then(function(content) {
// see FileSaver.js
saveAs(content, "my.zip");
});
});
JSZip supports promises as content: you can wrap each HTTP calls into promises and not explicitly wait.
The first function, downloadUrlAsPromise, wraps the xhr call into a Promise. The second function, downloadFirebaseImage, chains the promise from getDownloadURL with the promise of the first function. The result is a promise of the xhr content.
Once you have that, you can give directly the promise to JSZip like that:
zip.file(i+".png", downloadFirebaseImage(imagePath));
Full methods:
function downloadUrlAsPromise (url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = "arraybuffer";
xhr.onreadystatechange = function(evt) {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
resolve(xhr.response);
} else {
reject(new Error("Ajax error for " + url + ": " + xhr.status));
}
}
});
xhr.send();
});
}
function downloadFirebaseImage(storageRef, path) {
var starsRef = storageRef.child(imagePath);
return starsRef.getDownloadURL().then(function(url) {
return downloadUrlAsPromise(url);
});
}
// ...
for (i = 1; i <= count; i++) {
console.log(path+i+".png");
var imagePath = path+i+".png";
zip.file(i+".png", downloadFirebaseImage(imagePath));
}
zip.generateAsync({type:"blob"})
.then(function(content) {
// see FileSaver.js
saveAs(content, "my.zip");
});
Related
I need to iterate over 151 pokemon, but the api endpoint looks like this https://pokeapi.co/api/v2/pokemon/1 where 1 is the first pokemon, and i need to iterate through to 151, calling a different endpoint every time. Is there a better way to do this? This is the code I have so far, and it doesn't work.
let pokeObj = {};
function pokeList() {
const url ='https://pokeapi.co/api/v2/pokemon/'
const xhr = new XMLHttpRequest();
xhr.onload = function() {
if (xhr.status === 200) {
for(let i = 1; i < 100; i++) {
pokeObj += JSON.parse(xhr.responseText);
xhr.open('GET', `${url + i.toString()}`, true);
xhr.send();
}
}
}
}
Try something like this:
(async () => {
let pokeObj = {};
const url ='https://pokeapi.co/api/v2/pokemon'
const xhr = new XMLHttpRequest();
for(let i = 1; i < 100; i++) {
const response = await new Promise(resolve => {
xhr.onload = function(e) {
resolve(e.target.response);
}
xhr.open('GET', `${url}/${i}`, true);
xhr.send();
});
console.log(response)
}
})();
Each request will be awaited before firing the next one, to be nice to the api server and not executing too many request in parallel.
I am sending a XMLHttpRequest to a MVC Controller and i am expecting to receive a file as a result.
When debugging with the browser i am getting a response that is ok , but i do not know why it is not as a file:
JS
window.submit=function () {
return new Promise((resolve, reject) => {
var form = document.getElementById("newTestForm");
var data = new FormData(form);
var xhr = new XMLHttpRequest();
var method = form.getAttribute('method');
var action = form.getAttribute('action');
xhr.open(method, action);
xhr.onload = function () {
if (this.status >= 200 && this.status < 300) {
resolve(xhr.response); //response looks ok...but no file starts downloading
}
else if (xhr.status != 200) {
reject("Failed to submit form with status" + xhr.status);
}
}
xhr.send(data);
});
}
Controller
[HttpPost]
[Route([Some Route])]
public async Task BenchAsync(object request)
{
try
{
string fileName = "results.txt";
object result = await service.RunAsync(request);
byte[] data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(result));
this.Response.ContentType = "application/octet-stream";
this.Response.ContentLength = data.Length;
using(MemoryStream stream=new MemoryStream(data))
{
await stream.CopyToAsync(this.Response.Body);
}
}
catch (Exception ex)
{
throw;
}
}
I have solved it thanks to this Post
It seems i had to transform the response into a BLOB , create a download link and point it towards this blob and the created link in order to download the file.
So the function looks like :
window.submit= function () {
return new Promise((resolve, reject) => {
var form = document.getElementById("newTestForm");
var data = new FormData(form);
var xhr = new XMLHttpRequest();
var method = form.getAttribute('method');
var action = form.getAttribute('action');
xhr.open(method, action);
xhr.onload = function () {
if (this.status >= 200 && this.status < 300) {
var blob = new Blob([this.response], { type: 'image/pdf' });
let a = document.createElement("a");
a.style = "display: none";
document.body.appendChild(a);
let url = window.URL.createObjectURL(blob);
a.href = url;
a.download = 'mytext.txt';
a.click();
window.URL.revokeObjectURL(url);
}
else if (xhr.status != 200) {
reject("Failed to submit form with status" + xhr.status);
}
}
xhr.send(data);
});
}
P.S i do not know what the type of the blob is named for txt but it works as well , given the right extension.
Please I need help !
To begin I don't speaking very well english sorry for the mistakes
So I'm tryng to receive a JSON Object with this code :
function uhttp(url){
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.responseType = 'json';
xhr.onload = function() {
var status = xhr.status;
if (status == 200) {
console.log(xhr.response)
return xhr.response;
}
};
xhr.send();
console.log('exit')
};
but when I use the function https like this :
`
( ()=>{
var perso =uhttp('bd.php?table=charac')
for (var i = 0; i < perso.lenght; i++) {
document.getElementbyID('container').append('<ul>'+perso[i].nom+'</ul>')
}
})()
`
perso he's undifined...
here the console of index.html
I've the impression that we'are exit the function before that whe receive the resonse and that is why the function return a null
Of course before to ask my question I'have make some research but no one working in my case....
Thank you for yours anwsers
It happens because you aren't returning value from uhttp() function but from anonymous function (xhr.onload).
In order to access this value after the AJAX call is over use promises:
function uhttp(url){
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.responseType = 'json';
xhr.onload = function() {
var status = xhr.status;
if (status == 200) {
resolve(xhr.response);
return;
}
reject();
};
xhr.onerror = function() {
reject()
};
xhr.send();
})
}
And use it like so:
uhttp('bd.php?table=charac').then(function(result) {
var person = result;
for (var i = 0; i < perso.lenght; i++) {
document.getElementbyID('container').append('<ul>'+perso[i].nom+'</ul>');
}
}).catch(function() {
// Logic on error
});
I want to show answer from XMLhttpRequest in other function (not in onreadystatechangefunction).
I have code
setInterval(function() {
let requestPromise = new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open('POST', "location?act=update&id=<?php echo $id; ?>", true);
xhr.send();
xhr.onreadystatechange = function(){
if(this.readyState==4){
if(this.status == 200){
if(this.responseText){
try{
var data = JSON.parse(this.responseText);
if(data.command=="list"){
var answerLat = parseFloat(data.lat);
var answerLng = parseFloat(data.lng);
var answerAccuracy = String(data.accuracy);
var answerTime = String(data.time);
resolve(answerLat); // Pump answerLat
resolve(answerLng);
resolve(answerAccuracy);
resolve(answerTime);
}
}catch(e){
}
}
}
}
}
});
requestPromise.then(googleMapsFunction); // googleMapsFunction will be called once the request is completed and will get answerLat as the argument
}, 20000);
For example: I have google map in other function. How I can load data (answerLat, answerLng, answerAccuracy and answerTime) from xmlhttpreqest to other function with map (function - googleMapsFunction)?
but when I use it I see error:
Uncaught (in promise) ReferenceError: answerLat is not defined
How I can accept it as a parameter?
I guess the problem is on promise resolving. Try to combine received data into single object and pass it to resolve()
setInterval(function() {
let requestPromise = new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open('POST', "location?act=update&id=<?php echo $id; ?>", true);
xhr.send();
xhr.onreadystatechange = function(){
if(this.readyState==4 && this.status == 200 && this.responseText){
try{
var data = JSON.parse(this.responseText);
if(data.command=="list"){
resolve({
answerLat: parseFloat(data.lat),
answerLng: parseFloat(data.lng),
answerAccuracy: data.accuracy,
answerTime: data.time
});
}
}catch(e){
reject(e)
}
}
}
});
requestPromise.then(googleMapsFunction); // googleMapsFunction will be called once the request is completed and will get answerLat as the argument
}, 20000);
const googleMapsFunction = (params) => {
const {answerLat, answerLng, answerAccuracy, answerTime} = params
// ... answerLat, answerLng, answerAccuracy, answerTime
}
This query works, but i want to add some optionnals parameters.
Alert.prototype.getUserFollowedChannels = async function (user) {
return new Promise((resolve, reject) =>{
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.twitch.tv/kraken/users/' + user+ '/follows/channels?client_id=' + this.clientId, true);
//xhr.open('GET', 'https://api.twitch.tv/kraken/users/' + user+ '/follows/channels?client_id=' + this.clientId+'?limit=100', true); // try with what i want
xhr.onreadystatechange = function () {
if (xhr.readyState != 4 || xhr.status != 200) return;
var follows = JSON.parse(xhr.responseText);
if (follows) resolve(follows);
else resolve("none");
}
xhr.send();
})
}
There is the doc of my query : https://dev.twitch.tv/docs/v5/reference/users/#get-user-follows
You can use something like query-string