I store Word files (.docx) using GridFS on the server. I would like to combine documents into a single Word file using the docx-builder NPM package.
This is how I upload files:
Meteor.methods({ uploadFiles: function (files) { check(files, [Object]); if (files.length < 1) throw new Meteor.Error("invalid-files", "No files were uploaded"); var documentPaths = []; _.each(files, function (file) { ActivityFiles.insert(file, function (error, fileObj) { if (error) { console.log("Could not upload file"); } else { documentPaths.push("/cfs/files/activities/" + fileObj._id); } }); }); return documentPaths; } })
How can I do this on the server side? I can only do this on the server side, because the package I use requires the fs package, which cannot be executed on the client side.
This is how I am working on it right now. From the client, I call the following method (which is declared as Meteor.method ):
print: function(programId) { // Get the program by ID. var program = Programs.findOne(programId); // Create a new document. var docx = new docxbuilder.Document(); // Go through all activities in the program. program.activityIds.forEach(function(activityId) { // Create a temporary server side folder to store activity files. const tempDir = fs.mkdtempSync('/tmp/'); // Get the activity by ID. var activity = Activities.findOne(activityId); // Get the document by ID. var document = ActivityFiles.findOne(activity.documents.pop()._id); // Declare file path to where file will be read. const filePath = tempDir + sep + document.name(); // Create stream to write to path. const fileStream = fs.createWriteStream(filePath); // Read from document, write to file. document.createReadStream().pipe(fileStream); // Insert into final document when finished writinf to file. fileStream.on('finish', () => { docx.insertDocxSync(filePath); // Delete file when operation is completed. fs.unlinkSync(filePath); }); }); // Save the merged document. docx.save('/tmp' + sep + 'output.docx', function (error) { if (error) { console.log(error); } // Insert into Collection so client can access merged document. Fiber = Npm.require('fibers'); Fiber(function() { ProgramFiles.insert('/tmp' + sep + 'output.docx'); }).run(); }); }
However, when I download the final document from the Client-side ProgramFiles collection, the document is an empty Word document.
What is wrong here?
I have included @FrederickStark answer in my code. Just stuck on this part now.
Here's another try:
'click .merge-icon': (e) => { var programId = Router.current().url.split('/').pop(); var programObj = Programs.findOne(programId); var insertedDocuments = []; programObj.activityIds.forEach(function(activityId) { var activityObj = Activities.findOne(activityId); var documentObj = ActivityFiles.findOne(activityObj.documents.pop()._id); JSZipUtils.getBinaryContent(documentObj.url(), callback); function callback(error, content) { var zip = new JSZip(content); var doc = new Docxtemplater().loadZip(zip); var xml = zip.files[doc.fileTypeConfig.textPath].asText(); xml = xml.substring(xml.indexOf("<w:body>") + 8); xml = xml.substring(0, xml.indexOf("</w:body>")); xml = xml.substring(0, xml.indexOf("<w:sectPr")); insertedDocuments.push(xml); } }); JSZipUtils.getBinaryContent('/assets/template.docx', callback); function callback(error, content) { var zip = new JSZip(content); var doc = new Docxtemplater().loadZip(zip); console.log(doc); setData(doc); } function setData(doc) { doc.setData({