I cant download a zip file in AngularJS (from Laravel response) - angularjs

I am trying to download a zip file from a Laravel API using Angular JS. I do not believe the issue is from Laravel.
Basically when the response comes and the download trigger is made it does not know its a .zip file, however the file itself is good. But then when I manually add the .zip extension in Angular JS in the file name the browser advises its a corrupt file.
If I do not add the extension, it downloads fine, and then if i rename the file with no extension in Windows and change it to test.zip it works perfectly as a zip file. This is how I know the data is good.
I have tried arraybuffer responseType and blob. With blob I am getting the download trigger, with arraybuffer nothing is happening (including no console errors).
Here is my JS controller code:
vm.downloadSelectedFiles = function() {
vm.selectedFiles = [];
angular.forEach(vm.fileDownloadList, function(value,index) {
if(value==1) {
vm.selectedFiles.push(index);
}
});
Data.downloadSelectedFiles(vm.selectedFiles,vm.stationIDToLookUp)
.then(function (data) {
var url = $window.URL || $window.webkitURL;
vm.fileUrl = url.createObjectURL(data.data);
var a = document.createElement("a");
a.href = vm.fileUrl;
a.download = 'test.zip';
//a.download = 'test';
a.click();
}).catch(function (err) {
});
}
Here is my JS service code
downloadSelectedFiles: function downloadSelectedFiles(selectedFiles,stationID) {
var apiBase = apiUrl + 'download-selected-files';
var config = {
//responseType: 'arraybuffer'
responseType: 'blob'
};
var data = {
selectedFiles: selectedFiles,
stationID: stationID
}
return $http.post(apiBase, data, config);
}
And just in case there is something relevant about the response from the API. Here is my Laravel code
public function downloadSelectedFiles(PublishDataRequest $requestData) {
return response()->file(storage_path() . '/app/files/test.zip');
}

Try setting the MIME type to application/zip:
Data.downloadSelectedFiles(vm.selectedFiles,vm.stationIDToLookUp)
.then(function (response) {
var blob = response.data;
var zipBlob = new Blob([blob], { type: "application/zip" });
var url = $window.URL || $window.webkitURL;
vm.fileUrl = url.createObjectURL(zipBlob);
var a = document.createElement("a");
a.href = vm.fileUrl;
a.download = 'test.zip';
//a.download = 'test';
a.click();
}).catch(function (response) {
console.log("ERROR", response);
throw response;
});

Related

Axios IE 11 issue, cannot download response type blob

axios.get("http://localhost:63542/api/v1/WorkInst",
{
responseType: 'arraybuffer',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/pdf'
}
})
.then((response) => {
console.log(response);
var blob = new Blob([response.data], {type: 'application/pdf'});
var downloadUrl = URL.createObjectURL(blob);
var a = document.createElement("a");
a.href= downloadUrl;
a.download = ("test.pdf");
a.click();
})
.catch((error) => console.log(error));
But instead of downloading, "Do you want to allow this website to open an app on your computer?" But it is working using google chrome and mozilla firefox. Badly need help on this
As far as I know, the Download attribute not support IE browser. So, in the IE and Edge browser, after getting the file data, you could use the msSaveOrOpenBlob method to download the file in IE and Edge browser, and in the Chrome or Firefox browser, you could create a hyperlink to download the file using the URL. More detail information, please check this sample:
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
//IE11 and the legacy version Edge support
console.log("IE & Edge");
let blob = new Blob([data], { type: "text/html" });
window.navigator.msSaveOrOpenBlob(blob, fileName);
} else {// other browsers
console.log("Other browsers");
var bl = new Blob([data], { type: "text/html" });
var a = document.createElement("a");
a.href = URL.createObjectURL(bl);
a.download = fileName;
a.hidden = true;
document.body.appendChild(a);
a.click();
}

File download using SuperAgent

I'm trying to download files from server using SuperAgent. Please find the code below.
downloadDocument(fileIdMongo) {
var request = require('superagent');
var apiBaseUrl = "api/downloadDoc";
var self = this;
var req = request.get(apiBaseUrl);
req.query({ id: fileIdMongo })
req.end(function(err, res) {
if (err) {
console.log("error ocurred");
} else {
var blob = new Blob([res.text], {
type: 'text/csv/jpeg/jpg/png/pdf/docx/doc;charset=utf8;'
});
var element = document.createElement('a');
document.body.appendChild(element);
element.download = "Capture.PNG";
element.href = window.URL.createObjectURL(blob);
element.style.display = '';
element.click();
}
});
}
I'm trying to get a .png file from the server. I tested server with PostMan rest client. I'm able to get the .png file. But the file is not visible when using SuperAgent.
Use the below line of code in the else part.
window.location= 'api/CommercialInvoice?item=' + item.id,'';
element.click();

AngularJS save image file sent from Web API 2

I have been trying to follow different posts on downloading a file sent from my Web API. So far I can get the file to come, it will open the download window and it will save. However, I cannot open it so something must be wrong somewhere.
Here is my AngularJS so far.
return $http({
url: State.Endpoint + "/api/account/picture",
method: "GET",
responseType: 'arrayBuffer'
}).then(function (data) {
var octetStreamMime = 'application/octet-stream';
var success = false;
var file = new Blob([data.data], {
type: "image/jpeg"
});
var fileUrl = URL.createObjectURL(file);
var a = document.createElement('a');
a.href = fileUrl;
a.target = "_blank";
a.download = "myFile.jpg";
document.body.appendChild(a);
a.click();
});
That will make my successfully download the image for me. However, this doesn't let me open the file so either something is still wrong on client side or server side.
Server Side Code:
[Route("picture")]
[HttpGet]
public HttpResponseMessage GetPictureBlob()
{
HttpResponseMessage response = null;
var localFilePath = HttpContext.Current.Server.MapPath("~/Content/Images/demo.jpg");
if (!File.Exists(localFilePath))
{
response = Request.CreateResponse(HttpStatusCode.Gone);
}
else
{
var fStream = new FileStream(localFilePath, FileMode.Open, FileAccess.Read);
// Serve the file to the client
response = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StreamContent(fStream)
};
response.Content.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment")
{
FileName = Path.GetFileName(fStream.Name)
};
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
//response.Headers.Add("content-type", "application/octet-stream");
}
return response;
}
The provided value 'arrayBuffer' is not a valid enum value of type XMLHttpRequestResponseType.
Use arraybuffer all lowercase:
$http({
url: State.Endpoint + "/api/account/picture",
method: "GET",
//responseType: 'arrayBuffer'
//USE arraybuffer lowercase
responseType: 'arraybuffer'
//OR
//responseType: 'blob'
})
When the responseType is not valid, the XHR API defaults to decoding the response as UTF-8. This corrupts binary files such as JPEG images.
For more information, see MDN XHR Web API - responseType.
Creating a Download Button
Instead of creating a <a download></a> element with JavaScript DOM manipulation, consider using the AngularJS framework.
This is an example of a Download button that becomes active after the data is loaded from the server:
<a download="data_{{files[0].name}}" xd-href="data">
<button ng-disabled="!data">Download</button>
</a>
The xdHref Directive
app.module("myApp").directive("xdHref", function() {
return function linkFn (scope, elem, attrs) {
scope.$watch(attrs.xdHref, function(newVal) {
if (newVal) {
elem.attr("href", newVal);
}
});
};
});
The DEMO on PLNKR.
I've done the very same thing with this code, where:
data: Data received from server
format: data format, it must be one of https://developer.mozilla.org/en-US/docs/Web/API/Blob/type
name: your file's name
Code:
function downloadBlobFile(data, format, name) {
// format must be one of https://developer.mozilla.org/en-US/docs/Web/API/Blob/type
var file = new Blob([data], {type: 'application/' + format});
file.lastModified = new Date();
file.name = name + '.' + format.trim().toLowerCase();
// guarantee IE compatibility
if($window.navigator && $window.navigator.msSaveOrOpenBlob) {
$window.navigator.msSaveOrOpenBlob(file, file.name);
}
//other web browser
else {
/**
* Because this technology's specification has not stabilized, compatibility has been
* checked here: https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL#Browser_compatibility
*/
var fileURL = $window.URL.createObjectURL(file);
/* trick for downloading the file, borrowed from:
http://stackoverflow.com/questions/19327749/javascript-blob-filename-without-link
*/
var a = angular.element("<a style='display: none;'/>").attr("href", fileURL).attr("download", file.name);
angular.element(document.body).append(a);
a[0].click();
$window.URL.revokeObjectURL(fileURL);
a.remove();
}
}
var a = document.createElement("a"); //Create <a>
a.href = "data:image/png;base64," + ImageBase64;
a.download = "Image.png"; //File name Here
a.click(); //Downloaded file
Simplest way worked for me

Angular FileSaver with blob and WebAPI . PDF downloaded is blank. But API url returns PDF with content

This is my API for returning a PDF with multiple images . Now when I invoke this with url it perfectly downloads the PDF with images . For eg two pages with images .
[HttpGet]
public async Task<IHttpActionResult> Download(Guid customDocId)
{
byte[] responseContent = await Task.FromResult(FileNetApiClientFactory.Get(customDocId).DownloadDocument(customDocId, "pdf", true));
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(responseContent),
StatusCode = HttpStatusCode.OK,
};
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = string.Concat(customDocId.ToString(), ".pdf") };
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
return ResponseMessage(response);
}
Now from angular I am using blob and FileSaver for saving the PDF . So when I download it . Then it just returns two pages but with no content. But it shows page 1 and page2 but they are blank.
Here is my angular code :
//saveAs method is from FileSaver.js
vm.download = function () {
documentService.download($scope.customDocumentId).then(function (fileData) {
var blob = new Blob([fileData], { type: 'application/pdf' });
saveAs(blob, $scope.customDocumentId + ".pdf");
}).catch(function () {
});
}
And the service :
function _download(customDocumentId) {
return Restangular
.one('customdocument', customDocumentId).one('download')
.get(null, { responseType: 'arraybuffer' });
}
Does anyone has any idea why is it returning the blank pages when saved with FileSaver, while with direct download it is perfectly fine with all content.
I had to change certain things in Restangular . It was the responseType had to be arrayBuffer or 'blob'. I haven't tried with arrayBuffer explicitly . The blob responsetype worked for me . The configurations were missing from restangular. So I made a little change in my service and voila ! It was working.
So the updated Service looks like this now . DocumentServicesRestangular is nothing but a factory wrapper with changed baseurl through RestangularConfigurer.
function _download(customDocumentId) {
return DocumentServicesRestangular.one('customdocument', customDocumentId).one('download')
.withHttpConfig({ responseType: 'blob' }).get();
}
Try Like this,
$scope.download = function() {
var a = document.createElement("a");
document.body.appendChild(a);
var requestParams=$scope.downloadObj;
a.style = "display: none";
sServices.doAPIRequest(Url)
.then(function(generateData) {
var file = new Blob([$scope.base64ToArrayBuffer(generateData)], {
type : 'application/pdf'
});
var fileName="Data";
var fileURL = URL.createObjectURL(file);
a.href = fileURL;
a.download = fileName;
a.click();
});
};
$scope.base64ToArrayBuffer=function(data)
{
var binaryString = window.atob(data);
var binaryLen = binaryString.length;
var bytes = new Uint8Array(binaryLen);
for (var i = 0; i < binaryLen; i++) {
var ascii = binaryString.charCodeAt(i);
bytes[i] = ascii;
}
return bytes;
};
I fixed this issue by changing the $http.get call in my service, so that the response type was set in the config argument:
return $http.get(apiTarget, { responseType: 'blob' });
If you are using FileSaver then this is the right syntax
var data = new Blob([response], { type: 'application/pdf;charset=utf-8' });
FileSaver.saveAs(data, filename);

Downloading a file from Mongoose in Angular

I've managed to upload a file and store it in my MongoDB, but now I want to be able to downlaod this file from the same mongoDB. In server-side I'm using the GridFS module in Mongoose to upload and download using the gfs-read/write-stream.
Downlaod code in Mongoose looks like :
app.post('/Download', function (req, res) {
grid.mongo = mongoose.mongo;
var gfs = grid(conn.db);
var readstream = gfs.createReadStream({
filename: 'Program.cs'
});
readstream.pipe(res);
})
In my angular i have this so far:
$scope.Download = function () {
$http.post(url + "/Download")
.success(function (res) {
console.log(res);
})
}
the console.log response is shown here
I want to save this content into a .cs file in my local file system, also want to be able to prompt the user for the download-path, How do I do this?
Try below code
app.post('/Download', function (req, res) {
var filenameId = "";// mention _id value of 'Program.cs'
var filename = 'Program.cs';
var _id = new ObjectID(filenameId );
var gfs = new Grid(conn.db, "yourfile_collection_name");// default value is fs
gfs.get(_id, function(err, data) {
if (err)
throw err;
res.setHeader('Content-Disposition','attachment; filename="' + filename + '"');
res.send(data);
});
};

Resources