I am unable to save this content as proper PDF using FileSaver.js
this is Angular code
$http(
{ url:root.api_root+'/appointments/generatePDF/'+$routeParams.id,
method:'GET'
}).then(function(res){ //
$log.log(res.data);
var blob = new Blob([res.data], { type: 'application/pdf' });
window.open(res.data);
// saveAs(blob, 'file.pdf');
});
this is TCPDF Backend code
$pdf->Output("php://output", 'F');
echo file_get_contents("php://output");
When downloading binary data such as PDF files, it is important to set the responseType property:
$http(
{ url:root.api_root+'/appointments/generatePDF/'+$routeParams.id,
method:'GET',
//IMPORTANT
responseType: 'blob'
}).then(function(res){ //
$log.log(res.data);
//var blob = new Blob([res.data], { type: 'application/pdf' });
//window.open(res.data);
var blob = res.data;
saveAs(blob, 'file.pdf');
});
If the responseType property is omitted, the XHR API defaults to processing the data as UTF-8 text. The process of decoding the data as UTF-8 text will corrupt binary files such as PDF or images.
For more information, see MDN Web API Reference - XHR ResponseType
Dependencies
AngularJS
FileSaver.js
Blob.js
Installation
Using bower: bower install angular-file-saver
Using npm: npm install angular-file-saver
Basic usage
Include ngFileSaver module into your project;
Pass both FileSaver and Blob services as dependencies;
Create a Blob object by
passing an array with data as the first argument and an object with set of options
as the second one: new Blob(['text'], { type: 'text/plain;charset=utf-8' });
Invoke FileSaver.saveAs with the following arguments:
data Blob: a Blob instance;
filename String: a custom filename (an extension is optional);
disableAutoBOM Boolean: (optional) Disable automatically provided Unicode text encoding hints.
You can do so by injecting FileSaver and Blob into the controller and then using the syntax as shown below:
angular.module('sample',['ngFileSaver'])
.controller('ConsultationDetailsController', ['$scope', 'FileSaver', 'Blob', function($scope, FileSaver, Blob){
$scope.download = function (fileName) {
$scope.isLoading = true;
downloadHttpService.getDocument(fileName)
.then(function (response) {
var data = response.data;
var status = response.status;
var header = response.headers();
var fileType = header['content-type'];
var blob = new Blob([data], { type: fileType });
FileSaver.saveAs(blob, originalFileName);
})
.catch(function (resp) {
// show error
})
.finally(function (data) {
// execute finally block.
});
};
}]);
if you want only the pdf type then you can hard coded define
fileType as 'application/pdf' like this var fileType= 'application/pdf';
Hope this solves your problem :)
Its work for me. Just try it.
$http(
{ url:root.api_root+'/appointments/generatePDF/'+$routeParams.id,
method:'GET'
}).then(function(res){
$log.log(res.data);
saveAs('data:application/pdf;base64,' + res.data, 'file.pdf');
});
Related
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;
});
In my controller I call a service that returns a promise
var onComplete = function(data) {
$scope.myImage = data;
};
In my service I make a call to get the image by passing url directly to the image itself:
return $http.get("http://someurl.com/someimagepath")
.then(function(response){
return response.data;
});
All the calls are succeeding and the response.data appears to be holding in an image inside:
����JFIF��;CREATOR: gd-jpeg v1.0 (using IJG JPEG v80), quality = 90
��C
��C
����"��
���}!1AQa"q2���#B��R��$
although I'm not sure if it actually does because I'm having trouble displaying it. I've tried (inside index.html)
<img ng-src="{{myImage}}">
and
<img ng-src="{{myImage}}.jpeg">
and
<img ng-src="data:image/JPEG;base64,{{myImage}}">
Ideas?
Is it possible to return an actual image from $http.get and convert its response back to image (jpeg, etc.)
Thanks!
None of the methods seems to be complete, this is a complete solution:
$http({
method: 'GET',
url: imageUrl,
responseType: 'arraybuffer'
}).then(function(response) {
console.log(response);
var str = _arrayBufferToBase64(response.data);
console.log(str);
// str is base64 encoded.
}, function(response) {
console.error('error in getting static img.');
});
function _arrayBufferToBase64(buffer) {
var binary = '';
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
}
Then I am able to use it directly:
<img data-ng-src="data:image/png;base64,{{img}}">
The function to convert arraybuffer into base64 is directly taken from ArrayBuffer to base64 encoded string
Just in case anyone needs it.
In my case, I had to send the request through angular's $http service, because of various transformers and other fancy stuff we do with it.
So based on the Mozilla's guide mentioned earlier, I came up with the following solution:
let getImageDataURL = (url, imageType = 'image/jpeg') => {
return $http.get(url, {responseType: 'arraybuffer'}).then((res) => {
let blob = new Blob([res.data], {type: imageType});
return (window.URL || window.webkitURL).createObjectURL(blob);
});
};
The basic idea is to set the responseType property of the underlying XHR request and the convert the binary content to data URL.
The image that's coming back is in binary encoding, rather than Base64.
Understandably, <img> tags don't support sourcing from binary through attributes, so you'll have to look at another solution.
You could try converting the binary encoding to Base64 at the client side using TypedArrays together with the btoa function. Then you'd be able to use
<img ng-src="data:image/JPEG;base64,{{myImage}}">
This guide a by Mozilla covers making an XHR request for and image and reading it directly into a UInt8Array. It should be a good starting place.
It's written for plain old Javascript, but translating it to Angular should be a good exercise if you are just learning the ropes.
By way of https://stackoverflow.com/a/43032560/418819, you can use "blob" as the responseType and very neatly get the data url with a FileReader.
$http.get( url, { responseType: "blob" } ).then((result) => {
var reader = new FileReader();
reader.readAsDataURL( result.data );
reader.onload = function (e) {
return e.target.result;
};
});
You can reference it like so:
<img data-ng-src="{{img}}">
I need to upload an image taken from my mobile device to my server. I found the angular-upload library to which makes reference. I need to do is to transform the image base 64, send it by post to my server because the server is where I will work with her. And the other, send from my server and work it from the application to run.
var server = URL_BASE+'addView/';
var trustAllHosts = true;
var ftOptions = new FileUploadOptions();
ftOptions.fileKey = 'file';
ftOptions.fileName = $scope.imagen.substr($scope.imagen.lastIndexOf('/') + 1);
ftOptions.mimeType = 'image/jpeg';
ftOptions.httpMethod = 'POST';
console.log(ftOptions);
$cordovaFileTransfer.upload(encodeURI(server), $scope.imagen, ftOptions, trustAllHosts)
.then(function(result) {
console.log(result)
}, function(err) {
// Error
console.log(err);
}, function (progress) {
});
ionic file transfer
I'm personally using Cordova file transfer for upload & download content from a server.
Base64 encoding
Don't know where is your image stored and how you retrieve it, but, either you specify that the image is base64 encode into the HTML file delimiter
OR
You transform your image using a canvas
See that post for more info : https://stackoverflow.com/a/20285053/3687474
You haven't specified what you really need so:
Here you have a factory
//Factory you register on your module
angular
.module('myApp')
.factory('sendBase64Image', sendBase64Image)
function sendBase64Image($http) {
var urlBase; //url to be filled in
var base64 = {};
base64.sendBase = function (baseImg) {
var request = $http({
method: "post",
url: urlBase,
headers: {
'Content-type': 'application/json'
},
data : baseImg
});
}
return base64;
}
You should then inject it via dependency injection to your controller and perform call to the server.
If you want to do something with a response use success() method to handle promise response.
I was wondering how I can save a file that is contained in a response from the server in angular ? (So that the file is automatically downloaded when the response arrives)
Edit :
I have a $http post method, and I get pdf data in the response. On success, I want to save the response data as a pdf file.
E. g :
$http({
method: 'POST',
url : 'theUrl',
data: //some array that is received
headers : //content type info
}
.success(function(response) { // I want to save the response as a pdf });
On angular 2... you can do:
import { saveAs } from 'browser-filesaver/FileSaver.js'
downloadFile(data: Response) {
var blob = new Blob([data], {type: 'application/x-tar'});
saveAs(blob, "report.tgz");
}
Using HTML5 FileSaver interface, this can be achieved:
https://github.com/eligrey/FileSaver.js/
Example solution:
//Call API to retrieve file stream using POST request
$http.post("URL", searchData, { responseType: 'arraybuffer' }).then(
response => {
//Download file from response
saveFileAs(response);
},
data => {
//raise error
}
);
function saveFileAs(response) {
var contentDisposition = response.headers("content-disposition");
//Retrieve file name from content-disposition
var fileName = contentDisposition.substr(contentDisposition.indexOf("filename=") + 9);
fileName = fileName.replace(/\"/g, "");
var contentType = response.headers("content-type");
var blob = new Blob([response.data], { type: contentType });
saveAs(blob, fileName);
}
You can't save the document as you don't have access to the users file system in a browser. You could send the URL of the pdf back, then trigger the browsers build in file save / open mechanism by adding a dummy iFrame to the body:
$http({
method: 'POST',
url : 'theUrl',
data: //some array that is received
headers : //content type info
}
.success(function (data) {
if ($('#iframe').length == 0) {
var $iframe = $('<iframe id="iframe" style="display: none"></iframe>');
$('body').append($iframe);
}
$('#iframe').attr('src', {{url to retrieve the file}})
})
I am trying to get a 'progress' event from AngularJS $http POST request for file upload.
After looking at $http upload file progress in AngularJS, I came across one recent angular.js git commit, that suppose to resolve the issue Add XHR progress event handling to $http and $httpBackend.
Did anyone achieve this working? And if so, can kindly show the example?
PS. I'd prefer to stay with $http rather than create my own XMLHttpRequest. The reason is that my backend expects to get json object combined with multipart file data. And the attempt to make through XMLHttpRequest is failing with error message that backend doesn't see the json object part of request "Required String parameter 'objData' is not present. The request sent by the client was syntactically incorrect." While in the POST message I see "Content-Disposition: form-data; name="objData"" in Firebug.
$scope.uploadFile = function() {
var url = buildUrl('/upload');
var data = {objData: $scope.data, fileData: $scope.file};
var formData = new FormData();
formData.append("objData", angular.toJson(data.objData));
formData.append("fileData", data.fileData);
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener("progress", uploadProgress, false);
xhr.open("POST", url);
xhr.setRequestHeader("Content-Type","application/json;charset=utf-8");
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xhr.send(formData);
};
At time of writing $http doesn't support the notify method of the new 1.2 $q. So you have to use jquery xhr. Its rather simple once set up:
Notice that we return a promise so your consumer of uploadFile would do uploadFile(..).then(success, fail, progress)
$scope.uploadFile = function() {
var deferred = $q.defer();
var getProgressListener = function(deferred) {
return function(event) {
//do some magic
deferred.notify(magic);
};
};
var formData = new FormData();
formData.append("objData", angular.toJson(data.objData));
formData.append("fileData", data.fileData);
$.ajax({
type: 'POST',
url: buildUrl('/upload'),
data: formData,
cache: false,
// Force this to be read from FormData
contentType: false,
processData: false,
success: function(response, textStatus, jqXHR) {
deferred.resolve(response);
},
error: function(jqXHR, textStatus, errorThrown) {
deferred.reject(errorThrown);
},
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
if (myXhr.upload) {
myXhr.upload.addEventListener(
'progress', getProgressListener(deferred), false);
} else {
$log.log('Upload progress is not supported.');
}
return myXhr;
}
});
return deferred.promise;
};