Using NodeJS with AppJS to Package Zip with JSZip - javascript

My original file wouldn't download using the local method so I decided to use Node.js, as it's already packed in AppJS, and still the zip file won't execute in AppJS.
$(".export").on("click", function() {
var fs = require("fs");
var JSZip = require("jszip");
var zip = new JSZip();
zip.file("hello.txt", "Hello node!");
var content = zip.generate({type:"nodebuffer"});
// saveAs(content, "test.zip");
fs.writeFile("test.zip", content, function(err) {
if (err) throw err;
});
});
body {
background: #fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://stuk.github.io/jszip/dist/jszip.min.js"></script>
<script src="http://stuk.github.io/jszip-utils/dist/jszip-utils.js"></script>
<script src="http://stuk.github.io/jszip/vendor/FileSaver.js"></script>
<button class="export">Download</button>
Note: I've tried saving files using the File API, but the only want I've been able to successfully write a file in AppJS is by using Node.js as seen below.
var fs = require("fs");
fs.writeFile("hello.txt", "Hi", function(err) {
if (err) throw err;
});

I wasn't using Node but instead doing something similar in the browser that required FileSaver.js as well.
Have you tried:
var JSZip = require('jszip');
var saveAs = require('filesaver.js');
var zip = new JSZip();
zip.file("hello.txt", "Hello node!");
var blob = zip.generate({type: 'blob'});
saveAs(blob, 'images.zip');
The main difference here using {type: 'blob'} instead of nodebuffer. I was successful setting the response type to arraybuffer using a simple XHR download module.
module.exports = function download(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
callback(null, xhr.response);
};
xhr.onerror = function(e) {
callback(status.response);
};
xhr.send(null);
};

Related

download a PDF with Javascript/Node.Js after generating data and storing the file into a path

I created a generator for PDF files that creates the file and sends to a specific path automatically after creation. Still I want to download it right after but didn't know how to do that. Any help would be appreciated. This is my generatorPdf.js :
module.exports={
pdfGenerator:function(data,pathfile){
var fonts = {
Roboto: {
normal: 'server/pdfgenerator/fonts/Roboto-Regular.ttf',
bold: 'server/pdfgenerator/fonts/Roboto-Medium.ttf',
italics: 'server/pdfgenerator/fonts/Roboto-Italic.ttf',
bolditalics: 'server/pdfgenerator/fonts/Roboto-MediumItalic.ttf'
}
};
var datePaiements='';
var dateFinPaiements='';
if(data.abonnement[0].datePaiement!=null)
datePaiements= new Date( data.abonnement[0].datePaiement.toString());
if(datePaiements!=='')
{
dateFinPaiements= ('0'+datePaiements.getDate()).slice(-2).toString()+'/'+('0'+(datePaiements.getMonth()+1)).slice(-2).toString()+'/'+(datePaiements.getFullYear()+1).toString();
datePaiements=('0'+datePaiements.getDate()).slice(-2).toString()+'/'+('0'+(datePaiements.getMonth()+1)).slice(-2).toString()+'/'+datePaiements.getFullYear().toString();
}
var dateFacture= new Date(data.abonnement[0].timestampCreation.toString());
dateFacture= ('0'+dateFacture.getDate()).slice(-2).toString()+'/'+('0'+(dateFacture.getMonth()+1)).slice(-2).toString()+'/'+dateFacture.getFullYear().toString();
var PdfPrinter = require('pdfmake/src/printer');
var printer = new PdfPrinter(fonts);
var fs = require('fs');
var dd = {
content: [ ..............],
footer:{.............}
}
try{
var pdfDoc = printer.createPdfKitDocument(dd);
if (fs.existsSync(pathfile)) {//server/pdfgenerator/documentpdf/basics21.pdf
fs.unlink(pathfile, (err) => {//server/pdfgenerator/documentpdf/basics21.pdf
if (err) {
console.error(err)
return
}
})
}
pdfDoc.pipe(fs.createWriteStream(pathfile)).on('finish',function(){//server/pdfgenerator/documentpdf/basics21.pdf
});
}
catch(e){
console.log(e);
return null;
}
}
}
and this is my remote method in Loopback to send the pdf to a path and where probably I have to do the download of the file:
cm_abonnements.getAbonnementById= async (options,req,res)=>{
const token = options && options.accessToken;
const userId = token && token.userId;
try{
if(userId!==null){
let dataComedien= await app.models.cm_comediens.getComedienByUser(userId);
let argAbn={};
const form = new formidable.IncomingForm();
var formPromise = await new Promise(function(resolve,reject){
form.parse(req,function(err,fields,files){
if(err)
{
reject(err);
return-1
}
console.log(fields.key)
argAbn.idAbonnement=fields.key;
resolve();
})
})
let dataFac=await cm_abonnements.find({where :{and :[{idAbonnement:argAbn.idAbonnement},{idComedien : dataComedien.idComedien}]}});
var data={abonnement:[]};
data.abonnement=dataFac;
var str_date= new Date(dataFac[0].timestampCreation.toString());
var nameFile= 'Fac_'+dataFac[0].idFacture+'_'+str_date.getFullYear().toString()+'-'+('0'+str_date.getMonth()+1).slice(-2).toString()+'-'+('0'+str_date.getDate()).slice(-2).toString()+'.pdf';
var path='public/upload/Comediens/'+dataComedien.idComedien.toString()+'/factures/'+nameFile;
createPdf.pdfGenerator(data,path);
return dataFac;
}
return null;
}
catch(e){
console.log(e);
return null;
}
}
cm_abonnements.remoteMethod(
'getAbonnementById',{
http:{
verb:'POST'
},
description:'Get detail facture by number facture',
accepts:[
{arg:"options", "type":"object","http":"optionsFromRequest"},
{ arg: 'req', type: 'object', 'http': {source: 'req'}},
{arg: 'res', type: 'object', 'http': {source: 'res'}}
],
returns:{arg:'data',root:true}
}
);
Any help would be appreciated. Thank you
You need to send the following HTTP headers:
Content-Type: application/pdf
Content-Disposition: inline; filename="download.pdf"
After data is generated and pdf file is stored, there are 2 steps left to implement the "download" feature:
Return HTTP response to browser, with Content-Type header as application/pdf, and Content-Disposition header as attachment; filename="yourname.pdf". Normally, this would be handled automatically by web framework. I'm not familiar with loopback, so take Express for example:
In generatorPdf.js, add a callback to listen the finish event:
pdfGenerator:function(data, pathfile, callback){
...
pdfDoc.pipe(fs.createWriteStream(pathfile)).on('finish', callback);
...
}
When pdfGenerator function is used, pass a callback function parameter. If the pdf work is "finished", return response to browser using res.download() (It's Express API, but I believe loopback has similar API as loopback is built on top of Express):
var nameFile=...
var path=...
createPdf.pdfGenerator(data, path, function() {
res.download(path, nameFile);
});
In browser side, if it's an AJAX request (I guess so, as you mentioned it is a POST request), you need to handle the request with some blob operation. Here is an example snippet, with explanation comment:
var req = new XMLHttpRequest();
req.open('POST', '/download', true); // Open an async AJAX request.
req.setRequestHeader('Content-Type', 'application/json'); // Send JSON data
req.responseType = 'blob'; // Define the expected data as blob
req.onreadystatechange = function () {
if (req.readyState === 4) {
if (req.status === 200) { // When data is received successfully
var data = req.response;
var defaultFilename = 'default.pdf';
// Or, you can get filename sent from backend through req.getResponseHeader('Content-Disposition')
if (typeof window.navigator.msSaveBlob === 'function') {
// If it is IE that support download blob directly.
window.navigator.msSaveBlob(data, defaultFilename);
} else {
var blob = data;
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = defaultFilename;
document.body.appendChild(link);
link.click(); // create an <a> element and simulate the click operation.
}
}
}
};
req.send(JSON.stringify({test: 'test'}));

JS FileSaver non interactive

I have an array of file to save by using a loop and i generate the name of each file. I want to save file directly (in non interactive way) without asking me to confirm. How can i do ?
Here is my code for saving file
var url = img.src.replace(/^data:image\/[^;]/, 'data:application/octet-stream');
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob'; //Set the response type to blob so xhr.response returns a blob
xhr.open('GET', url , true);
xhr.onreadystatechange = function () {
if (xhr.readyState == xhr.DONE) {
var filesaver = require('file-saver');
filesaver.saveAs(xhr.response, nameFile); // nameFile the name of file to be saved
}
};
xhr.send(); //Request is sent
Finally, i find a solution, instead of saving file, i write it by creating a new one.
for (var i = 0; i < tabForm.length; i++) {
var imgData = $('#affichageqr')[0].childNodes[1].childNodes[0].src;
var data = imgData.replace(/^data:image\/\w+;base64,/, '');
fs.writeFile(qrcode.getNomQRCode()+'.jpeg', data, {encoding: 'base64'}, function(err){
if (err) {
console.log('err', err);
}
console.log('success');
});
}

javascript sql.js giving error Uncaught Error: file is encrypted or is not a database

Here is my <script> tag in my HTML page giving me the error:
Uncaught Error: file is encrypted or is not a database
<script>
var file = "/data/myDB.sqlite";
var db = new SQL.Database(file);
db.run("SELECT * FROM WEBUSERS", function(err, rows) {
rows.forEach(function (row) {
console.log('WEBUSERS Created User: '+row.USERNAME);
});
});
</script>
As mentioned in the comments, the constructor doesn't take a string, it takes a Uint8Array containing the SQLite database.
One way to do this would be to use an ajax request to get your database as an arraybuffer and transform it into a Uint8Array.
var file = "/data/myDB.sqlite";
var xhr = new XMLHttpRequest();
xhr.open('GET', file, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function() {
var data = new Uint8Array(this.response);
var db = new SQL.Database(data);
db.run("SELECT * FROM WEBUSERS", function(err, rows) {
rows.forEach(function(row) {
console.log('WEBUSERS Created User: ' + row.USERNAME);
});
});
};
xhr.send();

open excel file with xlsx.js by path

Hi i want to open excel file with xlsx extension with xlsx.js library.
I can open file by html input but i want to open it by using file path.
I have this code extracted from xlsx.js demo:
function handleFile(e) {
rABS = false;
use_worker = false;
console.log(e);
var files = e.target.files;
var f = files[0]; {
var reader = new FileReader();
var name = f.name;
reader.onload = function (e) {
if (typeof console !== 'undefined')
console.log("onload", new Date(), rABS, use_worker);
var data = e.target.result;
console.log("target result >>>>>>>>> " + e.target.result);
if (use_worker) {
xw(data, process_wb);
} else {
var wb;
if (rABS) {
wb = X.read(data, {
type : 'binary'
});
} else {
var arr = fixdata(data);
wb = X.read(btoa(arr), {
type : 'base64'
});
}
process_wb(wb);
}
};
if (rABS)
reader.readAsBinaryString(f);
else
reader.readAsArrayBuffer(f);
}
}
I want something like this:
var file = new File([""],"C:\\Users\\PalFS\\Downloads\\Fiverr_Example_List (1).xlsx");
var data = file;
How to do this or how can i convert this file into arraybuffer like it is returned from, var data = e.target.result;.
Thanks
You could use --allow-file-access-from-files flag at chrome, chromium with XMLHttpRequest , .responseType set to "arraybuffer" to retrieve .xlsx file from local filesystem as ArrayBuffer; set new File() data to returned ArrayBuffer. Second parameter at new File() constructor should set the .name property of created file.
Launch /path/to/chrome --allow-file-access-from-files
var request = new XMLHttpRequest();
// may be necessary to escape path string?
request.open("GET", "C:\\Users\\PalFS\\Downloads\\Fiverr_Example_List (1).xlsx");
request.responseType = "arraybuffer";
request.onload = function () {
// this.response should be `ArrayBuffer` of `.xlsx` file
var file = new File(this.response, "Fiverr_Example_List.xlsx");
// do stuff with `file`
};
request.send();

How to download files using javascript asynchronously?

I'm building a Chrome extension to download a series of files from a site. The downloading function is derived from How to save a file from a URL with JavaScript.
The program structure is like:
function download()
{
while(there are still files to download)
{
saveFile(url);
}
}
But I find that all the files are actually written to disk at once after download() returns. And the addresses of those files start with blob: when examine from Chrome's downloads manager.
I wonder if I make the call to saveFile asynchronously, those files could be written one at a time.
Using promises, which are available in Chrome out of the box, you can define the functions like so:
// Download a file form a url.
function saveFile(url) {
return new Promise(function(resolve, reject) {
// Get file name from url.
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = function() {
resolve(xhr);
};
xhr.onerror = reject;
xhr.open('GET', url);
xhr.send();
}).then(function(xhr) {
var filename = url.substring(url.lastIndexOf("/") + 1).split("?")[0];
var a = document.createElement('a');
a.href = window.URL.createObjectURL(xhr.response); // xhr.response is a blob
a.download = filename; // Set the file name.
a.style.display = 'none';
document.body.appendChild(a);
a.click();
return xhr;
});
}
function download(urls) {
return Promise.all(urls.map(saveFile));
}
Using it:
download.then(function() {
alert("all files downloaded");
}).catch(function(e) {
alert("something went wrong: " + e);
});
If you want to wait for 1 file to download before proceeding with next, the download function should be written like:
function download(urls) {
var cur = Promise.resolve();
urls.forEach(function(url) {
cur = cur.then(function() {
return saveFile(url);
});
});
return cur;
}
Usage is same as before.

Categories