I have a need to generate the received data in excel, however I am facing the problem of accessing a static file on my server
I use NuxtJS + VUE a static Excel file is located in my /static folder
/static/Excel.xlsx
/static/Word.docx
If I try to access via FileReader () then I get the error
var workBook = new Excel.Workbook();
workBook.xlsx.readFile("/Excel.xlsx").then(function() {
const ws = workbook.getWorksheet("Sheet1");
cell = ws.getCell("A1").value;
console.log(cell);
});
Error:
TypeError: Cannot read property 'F_OK' of undefined
This error, as I understood from the discussions, is related to browser security.
I would not want to violate the security of the browser and the application to access the file.
The option according to which the user loads the template himself is a little inconvenient, you have to do a lot of unnecessary actions
Link to solution on https://github.com/
at the same time I found a solution for Word using package: docxtemplater - it uses JSZipUtils
and the example with Word works fine, however the module for xlsx is very expensive for me
loadFile(url, callback) {
JSZipUtils.getBinaryContent(url, callback);
},
this.loadFile("/Word.docx", function(error, content) {
if (error) {
throw error;
}
var zip = new JSZip(content);
var doc = new Docxtemplater();
doc.loadZip(zip);
//... getting data from the database and inserting it into the Word template
});
Is it possible to somehow use the JSZipUtils package to implement access to Excel? or have
another way is it different to get an instance of a static file without violating security?
Related
I am using a node sever to send a table from a sqlite db to the browser. This table contains filename and path of a pdf file that I want to render on the browser. Until now I was using hard coded paths for the the pdf file and rendering. But now i have setup a get route and a controller in node such that whenever '/content' is hit in browser , the server queries the database and and sends the data to the client. To the send the data I am using
res.render('content/index',{data:queryData});
Now, how do I access this data using client side javascript so that I can pass the path of the pdf file to the function that renders the pdf? I have done research and the nearest answer I got was using XMLHttpRequest. I tried this method
var xhr = new XMLHttpRequest();
const path = "http://localhost:3000/content";
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200)
{
var myResponseText = xhr.responseText;
console.log(myResponseText);
}
};
xhr.open('get', path, true);
xhr.send();
When I do this I get the entire html code for the view. Not the data I expected. How do I solve this issue. I have done some more reading while writing this post and I suppose. I have set a header somewhere? But the documentation says
app.render(view, [locals], callback)
which means res.render can take local variables, shouldn't be setting the headers?
You should return json instead of render template:
app.get('content/index', (req, res) => {
res.json({data: queryData});
});
I am using pdf.js
PDF.js needs the PDF file, e.g.:
pdfjsLib.getDocument('helloworld.pdf')
I'm assuming your queryData goes something like this:
{ filename: 'file.pdf', path: './path/to/file.pdf' }
I'm not sure what's in your content/index or what path this is on, but you obviously need to find a way to make your PDF file ('./path/to/file.pdf') available (as a download). See Express's built-in static server or res.download() to do that.
Once you have the PDF file available as a download, plug that path into PDF.js's .getDocument('/content/file.pdf') and do the rest to render the PDF onto the canvas or whatever.
Hope that helps.
My app is created with mean and I am a user of docker too. The purpose of my app is to create and download a CSV file. I already created my file, compressed it and placed it in a temp folder (the file will be removed after the download). This part is in the nodejs server side and works without problems.
I already use several things like (res.download) which is supposed to download directly the file in the browser but nothing append. I tried to use blob in the angularjs part but it doesn't work.
The getData function creates and compresses the file (it exists I can reach it directly when I look where the app is saved).
exports.getData = function getData(req, res, next){
var listRequest = req.body.params.listURL;
var stringTags = req.body.params.tagString;
//The name of the compressed CSV file
var nameFile = req.body.params.fileName;
var query = url.parse(req.url, true).query;
//The function which create the file
ApollineData.getData(listRequest, stringTags, nameFile)
.then(function (response){
var filePath = '/opt/mean.js/modules/apolline/client/CSVDownload/'+response;
const file = fs.createReadStream(filePath);
res.download(filePath, response);
})
.catch(function (response){
console.log(response);
});
};
My main problem is to download this file directly in the browser without using any variable because it could be huge (like several GB). I want to download it and then delete it.
There is nothing wrong with res.download
Probably the reason why res.download don't work for you is b/c you are using AJAX to fetch the resource, Do a regular navigation. Or if it requires some post data and another method: create a form and submit.
Total nodejs newbie here. I am using meme-maker package to generate meme. However I want to create meme with image from url
var fileName = 'https://imgflip.com/s/meme/Futurama-Fry.jpg';
var memeMaker = require('meme-maker')
var options = {
image: fileName, // Required
outfile: 'meme.png', // Required
topText: 'top', // Required
bottomText: 'bottom', // Optional
}
memeMaker(options, function(err) {
if(err) throw new Error(err)
console.log('Image saved: ')
});
However I get error: Error: File does not exist: https://imgflip.com/s/meme/Futurama-Fry.jpg
How to read file from url and make meme?
If you go read the documentation of meme-maker you will see that it only supports local images and not URL's.
You will need to download the image first then use the local address. Go have a look at request
That library does not look like it supports URLs. The image param presumably takes a file path on the local system. If you want to use the URL to make a meme, you will have to:
Download that image from the URL using AJAX or something similar, store it to a file on the disk and get it's local path.
Pass the local file path of the file to the library
Get the generated meme path (and enable download if needed) and do clean up like deleting the old image, for example
I just started working with the Microsoft Azure Storage SDK for NodeJS (https://github.com/Azure/azure-storage-node) and already successfully uploaded my first pdf files to the cloud storage.
However, now I started looking at the documentation, in order to download my files as a node_buffer (so I dont have to use fs.createWriteStream), however the documentation is not giving any examples of how this works. The only thing they are writing is "There are also several ways to download files. For example, getFileToStream downloads the file to a stream:", but then they only show one example, which is using the fs.createWriteStream, which I dont want to use.
I was also not able to find anything on Google that really helped me, so I was wondering if anybody has experience with doing this and could share a code sample with me?
The getFileToStream function need a writable stream as param. If you want all the data wrote to a Buffer instead of a file, you just need to create a custom writable stream.
const { Writable } = require('stream');
let bufferArray = [];
const myWriteStream = new Writable({
write(chunk, encoding, callback) {
bufferArray.push(...chunk)
callback();
}
});
myWriteStream.on('finish', function () {
// all the data is stored inside this dataBuffer
let dataBuffer = Buffer.from(bufferArray);
})
then pass myWriteStream to getFileToStream function
fileService.getFileToStream('taskshare', 'taskdirectory', 'taskfile', myWriteStream, function(error, result, response) {
if (!error) {
// file retrieved
}
});
At the moment, due to the security policy Chromium can not read local files via ajax without --allow-file-access-from-files. But I currently need to create a web application where the database is a xml-file (in the extreme case, json), located in one dir with index.html. It is understood that the user can run this application locally. Are there workarounds for reading xml- (json-) file, without wrapping it in a function and change to js extension?
loadXMLFile('./file.xml').then(xml => {
// working with xml
});
function loadXMLFile(filename) {
return new Promise(function(resolve, reject) {
if('ActiveXObject' in window) {
// If is IE
var xmlDoc = new ActiveXObject('Microsoft.XMLDOM');
xmlDoc.async = false;
xmlDoc.load(filename);
resolve(xmlDoc.xml);
} else {
/*
* how to read xml file if is not IE?
* ...
* resolve(something);
*/
}
}
}
Accessing file: protocol at chromium using XMLHttpRequest() or <link> element without --allow-file-access-from-files flag set at chromium instance launch is not enabled by default.
--allow-file-access-from-files
By default, file:// URIs cannot read other file:// URIs. This is an
override for developers who need the old behavior for testing.
At the moment, due to the security policy Chromium can not read local
files via ajax without --allow-file-access-from-files. But I
currently need to create a web application where the database is a
xml-file (in the extreme case, json), located in one dir with
index.html. It is understood that the user can run this application
locally. Are there workarounds for reading xml- (json-) file, without
wrapping it in a function and change to js extension?
If user is aware that local files are to be used by the application you can utilize <input type="file"> element for user to upload file from user local filesystem, process file using FileReader, then proceed with application.
Else, advise user that use of application requires launching chromium with --allow-file-access-from-files flag set, which can be done by creating a launcher for this purpose, specifying a different user data directory for the instance of chromium. The launcher could be, for example
/usr/bin/chromium-browser --user-data-dir="/home/user/.config/chromium-temp" --allow-file-access-from-files
See also How do I make the Google Chrome flag “--allow-file-access-from-files” permanent?
The above command could also be run at terminal
$ /usr/bin/chromium-browser --user-data-dir="/home/user/.config/chromium-temp" --allow-file-access-from-files
without creating a desktop launcher; where when the instance of chromium is closed run
$ rm -rf /home/user/.config/chromium-temp
to remove the configuration folder for the instance of chromium.
Once the flag is set, user can include <link> element with rel="import" attribute and href pointing to local file and type set to "application/xml", for option other than XMLHttpRequest to get file. Access XML document using
const doc = document.querySelector("link[rel=import]").import;
See Is there a way to know if a link/script is still pending or has it failed.
Another alternative, though more involved, would be to use requestFileSystem to to store the file at LocalFileSystem.
See
How to use webkitRequestFileSystem at file: protocol
jQuery File Upload Plugin: Is possible to preserve the structure of uploaded folders?
How to Write in file (user directory) using JavaScript?
Or create or modify a chrome app and use
chrome.fileSystem
See GoogleChrome/chrome-app-samples/filesystem-access.
The simplest approach would be to provide a means for file upload by affirmative user action; process the uploaded file, then proceed with the application.
const reader = new FileReader;
const parser = new DOMParser;
const startApp = function startApp(xml) {
return Promise.resolve(xml || doc)
};
const fileUpload = document.getElementById("fileupload");
const label = document.querySelector("label[for=fileupload]");
const handleAppStart = function handleStartApp(xml) {
console.log("xml document:", xml);
label.innerHTML = currentFileName + " successfully uploaded";
// do app stuff
}
const handleError = function handleError(err) {
console.error(err)
}
let doc;
let currentFileName;
reader.addEventListener("loadend", handleFileRead);
reader.addEventListener("error", handleError);
function handleFileRead(event) {
label.innerHTML = "";
currentFileName = "";
try {
doc = parser.parseFromString(reader.result, "application/xml");
fileUpload.value = "";
startApp(doc)
.then(function(data) {
handleAppStart(data)
})
.catch(handleError);
} catch (e) {
handleError(e);
}
}
function handleFileUpload(event) {
let file = fileUpload.files[0];
if (/xml/.test(file.type)) {
reader.readAsText(file);
currentFileName = file.name;
}
}
fileUpload.addEventListener("change", handleFileUpload)
<input type="file" name="fileupload" id="fileupload" accept=".xml" />
<label for="fileupload"></label>
use document.implementation.createDocument("", "", null)
instead of new ActiveXObject('Microsoft.XMLDOM').
You can find the API through GOOGLE. Good luck.
If I understand correctly, the deliverable is intended to run locally so you will not be able to set any flags for local file access on a user's machine. Something I've done in a pinch is to pack it up as an executable with something like nw.js and keep the external data files. Otherwise, you're probably looking at loading as script using a JSON schema in a JS file.
I had a similar problem before. I solved by simply embedding the XML file into the HTML using PHP. Since the application is loaded locally from disk, size, cache etc. are not a concern.
If you're using Webpack, you can instead directly import the file using a loader like this or this, in which case the file is included into the resulting bundled javascript.
You can load XML through a string of text using DOMParser, Just load your file and parse the text using the .parseFromString. You could use an if statement containing (window.DOMParser) to check if the DOMParser is supported