Generate multiple docs and zip for download - javascript

I'm currently using docx.js in my react application I have setup with AWS Amplify (node backend). I am generating multiple documents and am saving them separately using the packer to generate the document as a blob and then use FileSaver.js's saveAs function to download. See code sample below:
const aDoc = new Document();
const bDoc = new Document();
const cDoc = new Document();
// Code that adds content to each doc
// Use packer to generate document as blob and download using FileSaver
Packer.toBlob(aDoc).then((blob) => {
// saveAs from FileSaver will download the file
FileSaver(blob, "aDoc.docx");
});
Packer.toBlob(bDoc).then((blob) => {
// saveAs from FileSaver will download the file
FileSaver(blob, "bDoc.docx");
});
Packer.toBlob(cDoc).then((blob) => {
// saveAs from FileSaver will download the file
FileSaver(blob, "cDoc.docx");
});
Now I'm wondering, how can I instead put these all into a ZIP file and have the user download that instead? Haven't really found much around, just this, which seems more like a workaround as it uses timeout to avoid issues when there are many documents--I'd rather avoid that and have it download in an archive instead. I've seen some libraries, like JSZip mentioned, but don't really understand how to get what docx.js is giving me into the archive.

Take a look at using JSZip - https://www.npmjs.com/package/jszip
I have reworked some code I used within a POC to how I believe it may work with your project and the code above.
var JSZip = require('jszip')
const Demo = () => {
const demoClick = () => {
var zip = new JSZip()
const zipFilename = 'test.zip'
const blobs = []
Packer.toBlob(aDoc).then((blob) => {
blobs.push(blob)
})
// repeat if needed
var urlArr = blobs // this will be your set of blobs you are downloading on their own right now.
urlArr.forEach(function (url) {
var filename = 'test.docx'
zip.file(filename, url, { binary: true })
})
zip.generateAsync({ type: 'blob' }).then(function (content) {
// you may need to work the content into a zip blob like this depending how FileSaver takes it
const zipContents = URL.createObjectURL(content)
//or
const zipContents = new Blob([content], {
type: 'application/zip'
})
// saveAs from FileSaver will download the file
FileSaver(content, zipFilename)
})
}
return <button onClick={demoClick}>demo</button>
}
If FileSaver doesn't like the format of the ZIP you could then use a more simple non imported download/save method
const zipContents = URL.createObjectURL(content)
if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(content, zipFilename)
} else if (isIOS && isChrome) {
window.open(zipContents, '_blank')
} else {
const link = document.createElement('a')
link.href = zipContents
link.target = '_blank'
link.download = zipFilename
link.click()
}

Related

unzipping downloaded zip repo from remote repository before saving in browser

I download a zip file from remote repo. Now I want to unzip that before saving to local system. How to do that in browser itself ? No need to unzip explicitly outside of browser
You can use a library like JSZip or fflate to unzip in the browser. You download the file, unzip, and save. Since fflate is faster, I'll use it.
const downloadFilesFromZip = async url => {
console.log('Downloading from ' + url + '...');
const unzipper = new fflate.Unzip();
unzipper.register(fflate.AsyncUnzipInflate);
unzipper.onfile = file => {
console.log("Got", file.name);
if (file.originalSize) {
console.log("Original size:", file.originalSize);
}
const rs = new ReadableStream({
start(controller) {
file.ondata = (err, dat, final) => {
controller.enqueue(dat);
if (final) controller.close();
}
file.start();
}
});
streamSaver.createWriteStream(
file.name,
rs
);
}
const res = await fetch(url);
const reader = res.body.getReader();
while (true) {
const { value, done } = await reader.read();
if (done) {
unzipper.push(new Uint8Array(0), true);
break;
}
unzipper.push(value);
}
}
// Call downloadFilesFromZip to download all files from a URL
// downloadFilesFromZip('https://your-url.com/file.zip');
downloadFilesFromZip(
'https://cors-anywhere.herokuapp.com/' +
'https://github.com/101arrowz/fflate/archive/master.zip'
)
<script src="https://cdn.jsdelivr.net/npm/streamsaver#2.0.3/StreamSaver.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/fflate#0.6.4/umd/index.js"></script>
StackOverflow doesn't allow downloads from answers, so it doesn't work properly, but the console will show the files that fflate found. Also, you need to go to this link and allow access before running that snippet.

Reactjs How to download file from Azure Storage Container

I am working on reactjs/typescript applications. I am trying to download some files from azure storage v2. Below is the sample path I am supposed to download files. In this path, enrichment is the container name, and the rest all are folders. I am trying to download the last modified file from reportdocument folder.
enrichment/report/SAR-1234-56/reportdocument/file1.docs
I tried something below.
#action
public async reportDownload(sarNumber: string) {
let storage = globals.getGlobals('StorageAccount03');
console.log(storage);
let containerName = globals.getGlobals('StorageAccount03ContainerName');
let marker = undefined;
let allUploadPromise: Array<Promise<unknown>> = [];
const config = {
path: `/Storage/getsastoken/?storageName=${storage}&containerName=${containerName}`,
method: "GET",
success: (url: any) => {
const containerURL: ContainerURL = new ContainerURL(
url,
StorageURL.newPipeline(new AnonymousCredential()));
const listBlobsResponse = containerURL.listBlobFlatSegment(
Aborter.none,
marker,
);
}
};
await handleRequest(config);
}
From here I am struggling to download the latest modified file from the above path.
can someone help me to fix this? Any help would be greatly appreciated. Thank you
It's better to use #azure/storage-blob library and then the code would be something like below instead of directly trying to call blob REST API like you were trying in your code which seems unnecessary reinventing the wheel. The library already does it for you. Refer this for details.
const { BlobServiceClient } = require("#azure/storage-blob");
const account = "<account name>";
const sas = "<service Shared Access Signature Token>";
const containerName = "<container name>";
const blobName = "<blob name>";
const blobServiceClient = new BlobServiceClient(`https://${account}.blob.core.windows.net${sas}`);
async function download() {
const containerClient = blobServiceClient.getContainerClient(containerName);
const blobClient = containerClient.getBlobClient(blobName);
// Get blob content from position 0 to the end
// In browsers, get downloaded data by accessing downloadBlockBlobResponse.blobBody
const downloadBlockBlobResponse = await blobClient.download();
const downloaded = await blobToString(await downloadBlockBlobResponse.blobBody);
console.log("Downloaded blob content", downloaded);
// [Browsers only] A helper method used to convert a browser Blob into string.
async function blobToString(blob) {
const fileReader = new FileReader();
return new Promise((resolve, reject) => {
fileReader.onloadend = (ev) => {
resolve(ev.target.result);
};
fileReader.onerror = reject;
fileReader.readAsText(blob);
});
}
}
The SAS token expiry bothers me.You cannot have a static SAS token that expires sooner unless we can set long expiry (user-delegation SAS token is short lived). Do we really have the capability to create the SAS token dynamically in javascript runtime? I think it's only possible in NodeJS runtime.

Saving JSON data from a Javascript page

I am trying to make a JavaScript/HTML local webpage that just gets opened from my local computer's files. I would like to make it save data in JSON form. But I've been having trouble finding out how to make a local JavaScript program read and write to a file in its same directory.
You can not write files to the local machine if you're using Javascript in the browser.
But you can download the JSON file to your local machine using Blob
You can use this code:
const data = {
key: "value"
};
const fileName = "data.json";
const saveFile = (() => {
const a = document.createElement("a");
document.body.appenChild(a);
return (data, filename) => {
const json = JSON.stringify(a);
const blob = new Blob([json], { type: "application/json" });
const url = window.URK.createObjectURL(blob);
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
}
})
saveData(data, fileName);

How to create download feature using ASP.NET Core 2.1 and React JS?

I'm using ASP.NET Core and React JS. I'm newbie to this both platforms. I have used Axios for requesting data and getting response from server. But I have not requested images or any kind of file from server. This time I'm working on Download feature where user will click on button and can download desired file which is of .png, .jpg, .pdf format. I'm not understanding how can server will send data? I read, I needed to send base64 data which is converted from blob format. But not understanding how to request data from client and how server will serve desired file. In DB, I have stored only address of file e.g. /images/img1.jpg. This file actually resides in wwwroot/images folder. I have used downloadjs for downloading which is working correctly but after downloading, that image is not readable as it does not have any content.
Please anyone help me to implement this feature.
First you need API to download data something like this
public async Task<IActionResult> Download(string filename)
{
if (filename == null)
return Content("filename not present");
var path = Path.Combine(
Directory.GetCurrentDirectory(),
"wwwroot", filename);
var memory = new MemoryStream();
using (var stream = new FileStream(path, FileMode.Open))
{
await stream.CopyToAsync(memory);
}
memory.Position = 0;
return File(memory, GetContentType(path), Path.GetFileName(path));
}
private string GetContentType(string path)
{
var types = GetMimeTypes();
var ext = Path.GetExtension(path).ToLowerInvariant();
return types[ext];
}
private Dictionary<string, string> GetMimeTypes()
{
return new Dictionary<string, string>
{
{".txt", "text/plain"},
{".pdf", "application/pdf"},
{".doc", "application/vnd.ms-word"},
{".docx", "application/vnd.ms-word"},
{".xls", "application/vnd.ms-excel"},
{".xlsx", "application/vnd.openxmlformats
officedocument.spreadsheetml.sheet"},
{".png", "image/png"},
{".jpg", "image/jpeg"},
{".jpeg", "image/jpeg"},
{".gif", "image/gif"},
{".csv", "text/csv"}
};
}
Then download file like this
axios({
url: 'your url',
method: 'POST', // Worked using POST or PUT. Prefer POST
responseType: 'blob', // important
}).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.pdf');
document.body.appendChild(link);
link.click();
});
Ref link

Is it possible to upload a text file to input in HTML/JS?

I have some input boxes in a HTML form that need to be updated when the form loads and these values need to be uploaded from a text file.
A similar question was also asked here:
Uploading Text File to Input in Html/JS
I have searched for this on the internet, but couldn't find any correct answer.
So I want to know whether it is possible or not?
If you wish to go the client side route, you'll be interested in the HTML5 FileReader API. Unfortunately, there is not wide browser support for this, so you may want to consider who will be using the functionality. Works in latest Chrome and Firefox, I think.
Here's a practical example: http://www.html5rocks.com/en/tutorials/file/dndfiles/#toc-reading-files
And I also read here to find the readAsText method: http://www.w3.org/TR/file-upload/#dfn-readAsText
I would do something like this (jQuery for brevity): http://jsfiddle.net/AjaDT/2/
Javascript
var fileInput = $('#files');
var uploadButton = $('#upload');
uploadButton.on('click', function() {
if (!window.FileReader) {
alert('Your browser is not supported');
return false;
}
var input = fileInput.get(0);
// Create a reader object
var reader = new FileReader();
if (input.files.length) {
var textFile = input.files[0];
// Read the file
reader.readAsText(textFile);
// When it's loaded, process it
$(reader).on('load', processFile);
} else {
alert('Please upload a file before continuing')
}
});
function processFile(e) {
var file = e.target.result,
results;
if (file && file.length) {
results = file.split("\n");
$('#name').val(results[0]);
$('#age').val(results[1]);
}
}
Text file
Jon
25
The other answer is great, but a bit outdated and it requires HTML & jQuery to run.
Here is how I do it, works in all modern browsers down to IE11.
/**
* Creates a file upload dialog and returns text in promise
* #returns {Promise<any>}
*/
function uploadText() {
return new Promise((resolve) => {
// create file input
const uploader = document.createElement('input')
uploader.type = 'file'
uploader.style.display = 'none'
// listen for files
uploader.addEventListener('change', () => {
const files = uploader.files
if (files.length) {
const reader = new FileReader()
reader.addEventListener('load', () => {
uploader.parentNode.removeChild(uploader)
resolve(reader.result)
})
reader.readAsText(files[0])
}
})
// trigger input
document.body.appendChild(uploader)
uploader.click()
})
}
// usage example
uploadText().then(text => {
console.log(text)
})
// async usage example
const text = await uploadText()

Categories

Resources