I may be running a bit behind, but this code snippet is designed to utilize your image array and generate GET requests accordingly. It will then proceed to execute all requests, add the responses to your zip file, and facilitate the download process.
I've included two options for downloading the file in case you're not keen on using the fileSaver. Feel free to choose whichever method suits you best.
EDIT:
If you happen to be utilizing an older version of rxjs, note that importing forkJoin
might require a different approach. Refer to the rxjs documentation for further guidance. Additionally, ensure that your backend permits file downloads to prevent CORS errors.
forkJoin Documentation
app.component.ts
import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { forkJoin } from "rxjs";
import { saveAs } from "file-saver";
import * as JSZip from 'jszip';
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
data = [
'http://yoururl/file.png',
'http://yoururl/file2.png'
];
getRequests = [];
constructor(private _http: HttpClient) {}
download() {
this.createGetRequets(this.data);
forkJoin(...this.getRequests)
.subscribe((res) => {
const zip = new JSZip();
res.forEach((f, i) => {
zip.file(`image${i}.png`, f);
});
/* With file saver */
// zip
// .generateAsync({ type: 'blob' })
// .then(blob => saveAs(blob, 'image.zip'));
/* Without file saver */
zip
.generateAsync({ type: 'blob' })
.then(blob => {
const a: any = document.createElement('a');
document.body.appendChild(a);
a.style = 'display: none';
const url = window.URL.createObjectURL(blob);
a.href = url;
a.download = 'image.zip';
a.click();
window.URL.revokeObjectURL(url);
});
});
}
private createGetRequets(data: string[]) {
data.forEach(url => this.getRequests.push(this._http.get(url, { responseType: 'blob' })));
}
}
app.component.html
<div style="text-align:center">
<button (click)="download()">Download</button>
</div>
In order to integrate jszip into my application, I had to update tsconfig.json with the path reference. The necessity of this step may vary based on your Angular version. Within "compilerOptions"
, include the following:
tsconfig.json
"paths": {
"jszip": [
"node_modules/jszip/dist/jszip.min.js"
]
}
UPDATE:
For those still leveraging the old HttpModule, the provided solution remains functional. However, transitioning to the newer HttpClientModule is advisable if feasible.
UPDATE2:
To accommodate various file types, consider altering the file extension when saving the downloaded files. This can enhance the versatility of the solution.
app.component.ts
import { Component } from "@angular/core";
import { Http, ResponseContentType } from "@angular/http"; // Different Import
import { forkJoin } from "rxjs";
import { saveAs } from "file-saver";
import * as JSZip from "jszip";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
/*
UPDATE 2
Create a Type map to handle differnet file types
*/
readonly MIME_TYPE_MAP = {
"image/png": "png",
"image/jpeg": "jpg",
"image/jpg": "jpg",
"image/gif": "gif"
};
data = [
"http://url/file.png",
"http://url/file.jpeg",
"http://url/file.gif"
];
getRequests = [];
constructor(private _http: Http) {} // Different Constructor
download() {
this.createGetRequets(this.data);
forkJoin(...this.getRequests).subscribe(res => {
const zip = new JSZip();
console.log(res);
/*
The return value is different when using the HttpModule.
Now you need do access the body of the response with ._body,
as you can see inside the forEach loop => f._body
*/
let fileExt: String; // UPDATE 2
res.forEach((f, i) => {
fileExt = this.MIME_TYPE_MAP[f._body.type]; // UPDATE 2, retrieve type from the response.
zip.file(`image${i}.${fileExt}`, f._body); // UPDATE 2, append the file extension when saving
});
zip
.generateAsync({ type: "blob" })
.then(blob => saveAs(blob, "image.zip"));
});
}
private createGetRequets(data: string[]) {
/*
Change your responseType to ResponseContentType.Blob
*/
data.forEach(url =>
this.getRequests.push(
this._http.get(url, { responseType: ResponseContentType.Blob })
)
);
}
}
UPDATE3:
To simplify handling of file types, extracting the file name from the URL can obviate the need for specifying file types individually. Here's an alternative approach:
import { Component } from "@angular/core";
import { Http, ResponseContentType } from "@angular/http";
import { forkJoin } from "rxjs";
import { saveAs } from "file-saver";
import * as JSZip from "jszip";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
data = ["http://url/file.png", "http://url/file.jpg", "http://url/file.gif"];
getRequests = [];
constructor(private _http: Http) {}
download() {
this.createGetRequets(this.data);
forkJoin(...this.getRequests).subscribe(res => {
const zip = new JSZip();
let fileName: String;
res.forEach((f, i) => {
fileName = f.url.substring(f.url.lastIndexOf("/") + 1); // extract filename from the response
zip.file(`${fileName}`, f._body); // use it as name, no need for explicit file type declaration
});
zip
.generateAsync({ type: "blob" })
.then(blob => saveAs(blob, "image.zip"));
});
}
private createGetRequets(data: string[]) {
data.forEach(url =>
this.getRequests.push(
this._http.get(url, { responseType: ResponseContentType.Blob })
)
);
}
}