Javascript - Print Blob Content Returned from API - javascript

I'm building a page for my angular2 web application where a user can select customers from a list and print off letters to mail them. These letters were uploaded as PDFs and are stored as varbinary in the database.
In the case of multiple selections, I'm simply appending byte[]'s so the user will print one document containing all of the letters to send to customers.
I'm able to pull the blob successfully from the API and return it with the content type application-pdf but then I don't know what to do with it from there.
Here's my Angular2 Component API Call:
this.printQueueService.getPrintContent(printRequests) //customers to receive letters
.subscribe((data: Blob) => {
var element: HTMLIFrameElement = <HTMLIFrameElement>document.getElementById('printFile');
element.innerText = data + ""; //what do I do with the blob?
element.contentWindow.print();
});
HTML Element:
<iframe id="printFile" style="display:none"></iframe>
I know I can just download the PDF and prompt the user to print using a PDF Viewer, but I'd rather not force users to go through extra steps.
I'd also rather not try to render the PDF in the browser and print because it assumes users have the proper plugins and browsers support it.
What options do I have for printing a blob in the browser?

As per suggestions from Daniel A. White, I solved this issue. I decided not to use an IFrame because these print files could be massive and the print() function includes the page name as footnotes.
Instead, I chose to open the generated PDF in a new tab as follows:
if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(data, "PrintedLetters.pdf"); //IE is the worst!!!
}
else {
var fileURL = URL.createObjectURL(data);
var a: HTMLAnchorElement = document.createElement('a');
a.href = fileURL;
a.target = '_blank';
document.body.appendChild(a);
a.click();
}

Related

extension crash on exporting stringified/encodeURIComponent data to file

It is about exporting extension data from options page.
I have array of objects, with stored page screenshots encoded in base64, and some other minor obj properties. I'm trying to export them with this code:
exp.onclick = expData;
function expData() {
chrome.storage.local.get('extData', function (result) {
var dataToSave = result.extData;
var strSt = JSON.stringify(dataToSave);
downloadFn('extData.txt', strSt);
});
}
function downloadFn(filename, text) {
var fLink = document.createElement('a');
fLink .setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
fLink .setAttribute('download', filename);
fLink .click();
}
On button click, get data from storage, stringify it, create fake link, set attributes and click it.
Code works fine if resulting file is under ~1.7 MB, but everything above that produce option page to crash and extension gets disabled.
I can console.log(strSt) after JSON.stringify and everything works fine no matter of the size, if I don't pass it to download function..
Is there anything I can do to fix the code and avoid crash?...or is there any limitation is size when using this methods?
I solved this, as Xan suggested, switching to chrome.downloads (it's extra permission, but works fine)
What I did is just replacing code in downloadFN function, it's cleaner that way
function downloadFn(filename, text) {
var eucTxt = encodeURIComponent(text);
chrome.downloads.download({'url': 'data:text/plain;charset=utf-8,'+eucTxt, 'saveAs': false, 'filename': filename});
}
note that using URL.createObjectURL(new Blob([ text ])) also produce same crashing of extension
EDIT:
as #dandavis pointed (and RobW confirmed), converting to Blob also works
(I had messed code that was producing crash)
This is a better way of saving data locally, because on browser internal downloads page, dataURL downloads can clutter page and if file is too big (long URL), it crashes browser. They are presented as actual URLs (which is raw saved data) while blob downloads are only with id
function downloadFn(filename, text) {
var vLink = document.createElement('a'),
vBlob = new Blob([text], {type: "octet/stream"}),
vUrl = window.URL.createObjectURL(vBlob);
vLink.setAttribute('href', vUrl);
vLink.setAttribute('download', filename);
vLink.click();
}

Let the User download the CSS file for iframe element

I am using two following JS functions to do the following steps:
Get iFrame html content generated via user interaction into a string
THEN Get the CSS stylesheet contained on my server named "myStylesheet.css" into a string
THEN Download those files to the reguesting user
var iframe = document.getElementById('frame');
function downloadFile(filename, text) {
var pom = document.createElement('a');
pom.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
pom.setAttribute('download', filename);
if (document.createEvent) {
var event = document.createEvent('MouseEvents');
event.initEvent('click', true, true);
pom.dispatchEvent(event);
}
else {
pom.click();
}
//example : downloadFile("hello.txt", "Hello World!") or for custom name filedownloadFile(myPageName +'.html', iFrameContent)
}
function publishWebsite(){
var htmlCodeForFrame = document.getElementById('frame').contentWindow.document.body.innerHTML;
var ccsCodeForFrame = "";
downloadFile("myWebsite.html", htmlCodeForFrame); //save html of frame into a file and download it to user
downloadFile("myStylesheet.css", ccsCodeForFrame); //save css of frame into a file and download it to user
}
My problem lies in turning a CSS stylesheet into a variable then download it (I want to stick with my download function for clarity because this is a Team Project and it's used in many other places.) to user. I wish this to be done in Javascript.
For modern browsers you could use the download-tag
Download
N.B: the file name is not required
(see browser support)
One other (rather nasty) trick is to create an ajax request with an invalid MIME-type, this prompts the browser to download the file since it can't render the view. Or you could use the application/octet-stream MIME-type.
I found myself using the following after some tinkering:
<iframe id="cssFrame" src="myStylesheet.css" style="display: none;"></iframe>
With conjunction of my code from the first post, I saved the content of the iframe to a string and saved the string in a file with .css extension. Works good.

encodeURI file download - crashing browser

I created a web application to clean up CSV/TSV data. The app allows me to upload a CSV file, read it, fix data, and then download a new CSV file with the correct data. One challenge I have run into is downloading files with more than ~ 2500 lines. The browser crashes with the following error message:
"Aw, Snap! Something went wrong while displaying this webpage..."
To work around this I have changed the programming to download multiple CSV files not exceeding 2500 lines until all the data is downloaded. I would then put together the downloaded CSV files into a final file. That's not the solution I am looking for. Working with files of well over 100,000 lines, I need to download all contents in 1 file, and not 40. I also need a front-end solution.
Following is the code for downloading the CSV file. I am creating a hidden link, encoding the contents of data array (each element has 1000 lines) and creating the path for the hidden link. I then trigger a click on the link to start the download.
var startDownload = function (data){
var hiddenElement = document.createElement('a');
var path = 'data:attachment/tsv,';
for (i=0;i<data.length;i++){
path += encodeURI(data[i]);
}
hiddenElement.href = path;
hiddenElement.target = '_blank';
hiddenElement.download = 'result.tsv';
hiddenElement.click();
}
In my case the above process works for ~ 2500 lines at a time. If I attempt to download bigger files, the browser crashes. What am I doing wrong, and how can I download bigger files without crashing the browser? The file that is crashing the browser has (12,000 rows by 48 columns)
p.s. I am doing all of this in Google Chrome, which allows for file upload. So the solution should work in Chrome.
I've experienced this problem before and the solution I found was to use Blobs to download the CSV. Essentially, you turn the csv data into a Blob, then use the URL API to create a URL to use in the link, eg:
var blob = new Blob([data], { type: 'text/csv' });
var hiddenElement = document.createElement('a');
hiddenElement.href = window.URL.createObjectURL(blob);
Blobs aren't supported in IE9, but if you just need Chrome support you should be fine.
I also faced same problem. I used this code,it will works fine. You can also try this.
if (window.navigator.msSaveBlob) {
window.navigator.msSaveBlob(new Blob([base64toBlob($.base64.encode(excelFile), 'text/csv')]),'data.csv');
} else {
var link = document.createElement('a');
link.download = 'data.csv';
// If u use chrome u can use webkitURL in place of URL
link.href = window.URL.createObjectURL(new Blob([base64toBlob($.base64.encode(excelFile), 'text/csv')]));
link.click();
}

Import to notepad using jquery

Is there any link for exporting the datas to notepad?
I have some fields like
Name,
Age, and
WorkingStatus
These are text and textarea...
I want to insert this datas to the notepad.Is there any demos or code available?
I don't know of any way to have the browser open notepad, but you can use HTML5 features to save a file as text, and then open it on your own inside notepad. Depending on the browser, you may need to trigger saving the file on the user side. Here's two references, which I'll summarize:
http://thiscouldbebetter.wordpress.com/2012/12/18/loading-editing-and-saving-a-text-file-in-html5-using-javascrip/
http://updates.html5rocks.com/2011/08/Saving-generated-files-on-the-client-side
Basically, you want to create and save a blob with your text. It should look something like this:
var arrayOfStuff = [];
arrayOfStuff.push("Name Age Working status");
arrayOfStuff.push("-----------------------------------------------");
arrayOfStuff.push(document.getElementById("name").value);
// etc
var blob = new Blob(arrayOfStuff, {type:'text/plain'});
// (the rest is copied directly from the wordpress link)
var downloadLink = document.createElement("a");
downloadLink.download = fileNameToSaveAs;
downloadLink.innerHTML = "Download File";
if (window.webkitURL != null)
{
// Chrome allows the link to be clicked programmatically.
downloadLink.href = window.webkitURL.createObjectURL(textFileAsBlob);
downloadLink.click();
}
else
{
// Firefox requires the user to actually click the link.
downloadLink.href = window.URL.createObjectURL(textFileAsBlob);
document.body.appendChild(downloadLink);
}
If notepad isn't a big deal, you should also be able to open this blob in an iframe as .txt, and then right-click and saveAs, if you prefer.
Edit
Ok, this was actually new for me to play with, so some of my older information wasn't quite right. Here's the javascript from the working fiddle:
var arrayOfStuff = [];
arrayOfStuff.push(document.getElementById("name").value + "\n");
arrayOfStuff.push(document.getElementById("email").value);
arrayOfStuff.push("\n");
arrayOfStuff.push(document.getElementById("phone").value);
arrayOfStuff.push("\n");
arrayOfStuff.push(document.getElementById("comments").value);
arrayOfStuff.push("\n");
alert(arrayOfStuff);
var blob = new Blob(arrayOfStuff, {type:'text/plain'});
var link = document.getElementById("downloadLink");
link.download = "details.txt";
link.href = window.URL.createObjectURL(blob);
The fiddle is at http://jsfiddle.net/xHH46/2/
There are a few lessons learned:
If you're on firefox, it gives you the option to open the .txt immediately in Notepad. However, notepad isn't paying attention to the linefeeds, whether they're \n or \n\r, appended to the immediate string or added separately, so I'd recommend using Wordpad instead. Or, you can save the file.
More importantly, realize that the link you display is based on whatever value is in the text when you create the blob. If you don't have defaults, you'll get an empty file, because all the fields are empty. The wordpress solution fixes this (and discusses using it within the past week), but the fix is ugly. Basically, you'd have to click on a button, and the button would then make a link appear, and that link would give you the good file.
You won't be able to do this with purely javascript. You need to generate the file server side and send it to the client.

Save File From Local Data in Javascript

Heres the scenario:
User comes to my website and opens a webpage with some javascript functionality.
User edits the data through javascript
User clicks on a save button to save the data, thing is, it seems like they shouldn't need to download this data because its already in javascript on the local machine.
Is it possible to save data from javascript (executing from a foreign webpage) without downloading a file from the server?
Any help would be much appreciated!
For saving data on the client-side, without any server interaction, the best I've seen is Downloadify, is a small JavaScript + Flash library allows you to generate and save files on the fly, directly in the browser...
Check this demo.
I came across this scenario when I wanted to initiate a download without using a server. I wrote this jQuery plugin that wraps up the content of a textarea/div in a Blob, then initiates a download of the Blob. Allows you to specify both file name and type..
jQuery.fn.downld = function (ops) {
this.each(function () {
var _ops = ops || {},
file_name = _ops.name || "downld_file",
file_type = _ops.type || "txt",
file_content = $(this).val() || $(this).html();
var _file = new Blob([file_content],{type:'application/octet-stream'});
window.URL = window.URL || window.webkitURL;
var a = document.createElement('a');
a.href = window.URL.createObjectURL(_file);
a.download = file_name+"."+file_type;
document.body.appendChild(a);
a.click(); $('a').last().remove();
});
}
Default Use : $("#element").downld();
Options : $("#element").downld({ name:"some_file_name", type:"html" });
Codepen example http://codepen.io/anon/pen/cAqzE
JavaScript is run in a sandboxed environment, meaning it only has access to specific browser resources. Specifically, it doesn't have access to the filesystem, or dynamic resources from other domains (web pages, javascript etc). Well, there are other things (I/O, devices), but you get the point.
You will need to post the data to the server which can invoke a file download, or use another technology such as flash, java applets, or silverlight. (i'm not sure about the support for this in the last 2, and I also wouldn't recommend using them, depends what it's for...)
The solution to download local/client-side contents via javascript is not straight forward. I have implemented one solution using smartclient-html-jsp.
Here is the solution:
I am in the project build on SmartClient. We need to download/export data of a grid
(table like structure).
We were using RESTish web services to serve the data from Server side. So I could not hit the url two times; one for grid and second time for export/transform the data to download.
What I did is made two JSPs namely: blank.jsp and export.jsp.
blank.jsp is literally blank, now I need to export the grid data
that I already have on client side.
Now when ever user asks to export the grid data, I do below:
a. Open a new window with url blank.jsp
b. using document.write I create a form in it with one field name text in it and set data to export inside it.
c. Now POST that form to export.jsp of same heirarchy.
d. Contents of export.jsp I am pasting below are self explanatory.
// code start
<%# page import="java.util.*,java.io.*,java.util.Enumeration"%>
<%
response.setContentType ("text/csv");
//set the header and also the Name by which user will be prompted to save
response.setHeader ("Content-Disposition", "attachment;filename=\"data.csv\"");
String contents = request.getParameter ("text");
if (!(contents!= null && contents!=""))
contents = "No data";
else
contents = contents.replaceAll ("NEW_LINE", "\n");
//Open an input stream to the file and post the file contents thru the
//servlet output stream to the client m/c
InputStream in = new ByteArrayInputStream(contents.getBytes ());
ServletOutputStream outs = response.getOutputStream();
int bit = 256;
int i = 0;
try {
while ((bit) >= 0) {
bit = in.read();
outs.write(bit);
}
//System.out.println("" +bit);
} catch (IOException ioe) {
ioe.printStackTrace(System.out);
}
outs.flush();
outs.close();
in.close();
%>
<HTML>
<HEAD>
</HEAD>
<BODY>
<script type="text/javascript">
try {window.close ();} catch (e) {alert (e);}
</script>
</BODY>
</HTML>
// code end
This code is tested and deployed/working in production environment, also this is cross-browser functionality.
Thanks
Shailendra
You can save a small amount of data in cookies.

Categories