15

I am trying to use docx.js to generate a Word document but I can't seem to get it to work.

I copied the raw code into the Google Chrome console after amending line 247 to fix a "'textAlign' undefined error"

if (inNode.style && inNode.style.textAlign){..}

Which makes the function convertContent available. The result of which is an Object e.g.

JSON.stringify( convertContent($('<p>Word!</p>)[0]) )

Results in -

"{"string":
      "<w:body>
            <w:p>
                <w:r>
                    <w:t xml:space=\"preserve\">Word!</w:t>
                </w:r>
            </w:p>
       </w:body>"
 ,"charSpaceCount":5
 ,"charCount":5,
 "pCount":1}"

I copied

<w:body>
    <w:p>
        <w:r>
            <w:t xml:space="preserve">Word!</w:t>
        </w:r>
    </w:p>
</w:body>

into Notepad++ and saved it as a file with an extension of 'docx' but when I open it in MS Word but it says 'cannot be opened because there is a problem with the contents'.

Am I missing some attribute or XML tags or something?

apokryfos
  • 38,771
  • 9
  • 70
  • 114
Peter
  • 4,493
  • 6
  • 41
  • 64
  • Have you tried using the Github repo of M4rio ? it has one example of use: https://github.com/MrRio/DOCX.js – edi9999 Jun 05 '13 at 09:30
  • After running the example code I am getting this error - `TypeError: Object function bound(var_args) { return func.apply(thisObject, args.concat(slice(arguments))); } has no method 'ajax'` – Peter Jun 05 '13 at 10:00
  • Have you loaded jQuery ? Dependencies are the following: ` ` – edi9999 Jun 05 '13 at 10:08
  • Yes I did. I am trying to setup a JSFiddle but I am not sure if it is an appropriate environment http://jsfiddle.net/iampeterbanjo/srK2u/6/ – Peter Jun 05 '13 at 11:13
  • You're right, thing is that the folder `blank` contains the data of an empty document, and the Javascript loads this blank document via `ajax` to create the new document – edi9999 Jun 05 '13 at 13:19

6 Answers6

22

You can generate a Docx Document from a template using docxtemplater (library I have created).

It can replace tags by their values (like a template engine), and also replace images in a paid version.

Here is a demo of the templating engine: https://docxtemplater.com/demo/

edi9999
  • 19,701
  • 13
  • 88
  • 127
4

This code can't work on a JSFiddle because of the ajaxCalls to local files (everything that is in the blankfolder), or you should enter all files in ByteArray format and use the jsFiddle echo API: http://doc.jsfiddle.net/use/echo.html

edi9999
  • 19,701
  • 13
  • 88
  • 127
  • 1
    Thanks. I have decided to do this server side using a library called https://docx.codeplex.com/ It would have been cool to do it with JavaScript but oh well. :-) – Peter Jun 05 '13 at 13:43
  • 2
    If you want a javascript only solution to generate docx from docx templates, have a look at the library I created: https://github.com/edi9999/docxgenjs – edi9999 Jun 05 '13 at 14:02
  • wow. that is really cool. can you use base64 images or canvas elements with it? do you have a demo page or hello_word.docx example(s)? – Peter Jun 05 '13 at 14:08
  • 1
    Sorry, I just found one of your examples - https://github.com/edi9999/docxgenjs/blob/master/examples/textTagging.html – Peter Jun 05 '13 at 14:12
  • 1
    yep, online examples can be found here: http://javascript-ninja.fr/docxgenjs/examples/simpleTagging.html# – edi9999 Jun 05 '13 at 14:15
  • That is awesome! I would be happy to accept this as an answer if you could post it as one. Thanks. – Peter Jun 05 '13 at 15:01
  • These comments relates to my answer (I can put more info on the post if you think it could be useful) – edi9999 Jun 05 '13 at 15:11
2

I know this is an older question and you already have an answer, but I struggled getting this to work for a day, so I thought I'd share my results.

Like you, I had to fix the textAlign bug by changing the line to this:

if (inNode.style && inNode.style.textAlign)

Also, it didn't handle HTML comments. So, I had to add the following line above the check for a "#text" node in the for loop:

if (inNodeChild.nodeName === '#comment') continue;

To create the docx was tricky since there is absolutely no documentation on this thing as of yet. But looking through the code, I see that it is expecting the HTML to be in a File object. For my purposes, I wanted to use the HTML I rendered, not some HTML file the user has to select to upload. So I had to trick it by making my own object with the same property that it was looking for and pass it in. To save it to the client, I use FileSaver.js, which requires a blob. I included this function that converts base64 into a blob. So my code to implement it is this:

var result = docx({ DOM: $('#myDiv')[0] });
var blob = b64toBlob(result.base64, "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
saveAs(blob, "test.docx");

In the end, this would work for simple Word documents, but isn't nearly sophisticated for anything more. I couldn't get any of my styles to render and I didn't even attempt to get images working. I've since abandoned this approach and am now researching DocxgenJS or some server-side solution.

Community
  • 1
  • 1
adam0101
  • 29,096
  • 21
  • 96
  • 174
2

You may find this link useful,

http://evidenceprime.github.io/html-docx-js/

An online demo here:

http://evidenceprime.github.io/html-docx-js/test/sample.html

user9869932
  • 6,571
  • 3
  • 55
  • 49
  • 1
    Thank you! I was able to save an image to a docx! I needed to `npm install` the following: `html-docx-js`, `brfs`, `coffeeify`, `coffeescript`, [`file-saver` (for `saveAs`)](https://github.com/eligrey/FileSaver.js) – Jesus is Lord Aug 21 '18 at 23:51
  • @WordsLikeJared how do you save image without tinymce? I don't think tinymce is needed right? – sg552 Feb 01 '20 at 13:47
0

You are doing the correct thing codewise, but your file is not a valid docx file. If you look through the docx() function in docx.js, you will see that a docx file is actually a zip containing several xml files.

0

I am using Open Xml SDK for JavaScript.

http://ericwhite.com/blog/open-xml-sdk-for-javascript/

Basically, on web server, I have a empty docx file as new template. when user in browser click new docx file, I will retrieve the empty docx file as template, convert it to BASE64 and return it as Ajax response.

in client scripts, you convert the BASE64 string to byte array and using openxmlsdk.js to load the byte array as an javascript OpenXmlPackage object.

once you have the package loaded, you can use regular OpenXmlPart to create a real document. (inserting image, creating table/row ).

the last step is stream it out to end user as a document. this part is security related. in my code I send it back to webserver and gets saved temporarily. and prepare a http response to notify end user to download it.

Check the URL above, there are useful samples of doing this in JavaScript.

Victor Xie
  • 148
  • 1
  • 9