here i am having below dynamic data like this
data = [
".jpg&text=test",
".jpg&text=testOne",
".png&text=testTwo"
]
on button click i want to get the all the images from those url's and save it as zip
Issue : when ever i am able download the file as zip and try to extract it i am getting error as could not open image.zip as archieve and if i save as single image also the image is not opening up and is there any way to store the
below is my code
downloadImageData(){
var blob = new Blob([this.data], { type: 'application/zip'' });
FileSaver.saveAs(blob,'image.zip');
}
here i am having both png & jpg and various type of data so what ever data the links will get has to downloaded as zip file is there any approach for angular 5+. i am using filesave angular package also
JS ZIP _body resp
By using the http module im getting the below data [
{
"_body": {
},
"status": 200,
"ok": true,
"statusText": "OK",
"headers": {
"date": [
"Sun",
" 25 Nov 2018 12:18:47 GMT"
],
"cache-control": [
"public",
" max-age=43200"
],
"expires": [
"Mon",
" 26 Nov 2018 00:18:47 GMT"
],
"content-disposition": [
"attachment; filename=2B.JPG"
],
"content-length": [
"40649"
],
"server": [
"Werkzeug/0.14.1 Python/2.7.13"
],
"content-type": [
"image/jpg"
]
},
"type": 2,
"url": "http://some url"
}
]
here i am having below dynamic data like this
data = [
"https://dummyimage./200x200/000/fff.jpg&text=test",
"https://dummyimage./200x200/000/fff.jpg&text=testOne",
"https://dummyimage./200x200/000/fff.png&text=testTwo"
]
on button click i want to get the all the images from those url's and save it as zip
Issue : when ever i am able download the file as zip and try to extract it i am getting error as could not open image.zip as archieve and if i save as single image also the image is not opening up and is there any way to store the
below is my code
downloadImageData(){
var blob = new Blob([this.data], { type: 'application/zip'' });
FileSaver.saveAs(blob,'image.zip');
}
here i am having both png & jpg and various type of data so what ever data the links will get has to downloaded as zip file is there any approach for angular 5+. i am using filesave angular package also
JS ZIP _body resp
By using the http module im getting the below data [
{
"_body": {
},
"status": 200,
"ok": true,
"statusText": "OK",
"headers": {
"date": [
"Sun",
" 25 Nov 2018 12:18:47 GMT"
],
"cache-control": [
"public",
" max-age=43200"
],
"expires": [
"Mon",
" 26 Nov 2018 00:18:47 GMT"
],
"content-disposition": [
"attachment; filename=2B.JPG"
],
"content-length": [
"40649"
],
"server": [
"Werkzeug/0.14.1 Python/2.7.13"
],
"content-type": [
"image/jpg"
]
},
"type": 2,
"url": "http://some url"
}
]
Share
Improve this question
edited Nov 25, 2018 at 12:40
Madpop
asked Nov 20, 2018 at 16:52
MadpopMadpop
7254 gold badges28 silver badges63 bronze badges
6
-
You have 3
'
in'application/zip'
, maybe it's an error from copying, but if you have it in your code then you should remove one – ams Commented Nov 22, 2018 at 18:15 - @ams That's typo error in application I have 2 only verified that – Madpop Commented Nov 22, 2018 at 18:46
- have you tried downloading the file without using FileSaver? For example with an a tag, I could provide an example if you want to. – ams Commented Nov 22, 2018 at 19:07
- 1 If this is all your code, the problem is, that you have to download the binary data first. You cannot simply add an array of URLs and make it magically be a zip file by providing a content type. In angular you'd use the HttpClient to download the files. – Christoph Lütjen Commented Nov 22, 2018 at 21:22
- @ams no i tried only using that as i thought it makes things simple & sure u can provide a sample by using the above urls – Madpop Commented Nov 23, 2018 at 3:49
2 Answers
Reset to default 4I have created a demo application here.
P.S: The code is for guidance only, and may not include standard coding practices but may guide you to create your own version of the solution.
I'm using jszip to zip file.
app.module.ts:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/mon/http';
import { AppComponent } from './app.ponent';
import * as JSZip from 'jszip';
import { saveAs } from 'file-saver';
@NgModule({
imports: [ BrowserModule, HttpClientModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
app.ponent.ts:
import { OnInit, Component } from '@angular/core';
import { HttpClient } from '@angular/mon/http';
import * as JSZip from 'jszip';
import { saveAs } from 'file-saver';
@Component({
selector: 'my-app',
template: `<button (click)='downloadZip()'>Download</button>`
})
export class AppComponent {
constructor(private http: HttpClient) {
}
downloadZip() {
this.loadSvgData("https://c.staticblitz./assets/client/icons/file-icons/angular-ponent-31179578a9a8a16512e9e90ade26549a.svg",
this.saveAsZip);
}
private loadSvgData(url: string, callback: Function) : void{
this.http.get(url, { responseType: "arraybuffer" })
.subscribe(x => callback(x));
}
private saveAsZip(content: Blob) : void{
var zip = new JSZip.default();
zip.file("image.svg", content);
zip.generateAsync({ type: "blob" })
.then(blob => saveAs(blob,'image.zip'));
};
}
Explanation:
The application only has one button, which on click will download an image file from the server using HttpClient
. It will zip downloaded data using jszip
and save it to browser using file-saver
.
I hope this helps!
I'm a little late, but this code will use your image array and create your GET requests. After that it will perform all requests and the responses will be added to your zip file and then downloaded.
I included two ways to download the file if you don't like to use the fileSaver. Pick whichever you prefer.
EDIT:
If you are using an old version of rxjs you'll have to import forkJoin
in a different way, consult the rxjs documentation.
Also be sure that your backend allows the download of files, otherwise you'll have CORS errors.
forkJoin Documentation
app.ponent.ts
import { Component } from "@angular/core";
import { HttpClient } from "@angular/mon/http";
import { forkJoin } from "rxjs";
import { saveAs } from "file-saver";
import * as JSZip from 'jszip';
@Component({
selector: "app-root",
templateUrl: "./app.ponent.html",
styleUrls: ["./app.ponent.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.ponent.html
<div style="text-align:center">
<button (click)="download()">Download</button>
</div>
I also had to include the path to jszip in my tsconfig.json. Depending on your version of angular you don't have to do this. Inside "pilerOptions"
add following:
tsconfig.json
"paths": {
"jszip": [
"node_modules/jszip/dist/jszip.min.js"
]
}
UPDATE:
Here is a solution with the old HttpModule, I tried it out and it works. I would suggest changing to the new HttpClientModule if possible.
UPDATE2:
Like I said in the ments, you can change the file extension when saving the file to handle different file types. This is an example and you can easily expand this solution.
app.ponent.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.ponent.html",
styleUrls: ["./app.ponent.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:
Solution which extracts the file name from the URL, this way the file type is not needed:
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.ponent.html",
styleUrls: ["./app.ponent.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, this way we don't need the file type anymore
});
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 })
)
);
}
}