Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zipping multiple documents in one zipfile fails #538

Closed
timm333 opened this issue Aug 4, 2020 · 4 comments
Closed

Zipping multiple documents in one zipfile fails #538

timm333 opened this issue Aug 4, 2020 · 4 comments

Comments

@timm333
Copy link

timm333 commented Aug 4, 2020

Environment

  • Version of docxtemplater : 3.17.9
  • Used docxtemplater-modules : none
  • Runner : Browser

How to reproduce my problem :

My template is the following : https://docxtemplater.com/tag-example.docx

With the following html file :

<html>
    <body>
        <button onclick="generate()">Generate document</button>
    </body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/docxtemplater/3.17.9/docxtemplater.js"></script>
    <script src="https://unpkg.com/pizzip@3.0.6/dist/pizzip.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.js"></script>
    <script src="https://unpkg.com/pizzip@3.0.6/dist/pizzip-utils.js"></script>

    <script>
    var zipDocs = new PizZip();
    function loadFile(url,callback){
        PizZipUtils.getBinaryContent(url,callback);
    }

    function generate() {

        loadFile("https://docxtemplater.com/tag-example.docx",function(error,content){
            if (error) { throw error };

            // The error object contains additional information when logged with JSON.stringify (it contains a properties object containing all suberrors).
            function replaceErrors(key, value) {
                if (value instanceof Error) {
                    return Object.getOwnPropertyNames(value).reduce(function(error, key) {
                        error[key] = value[key];
                        return error;
                    }, {});
                }
                return value;
            }

            function errorHandler(error) {
                console.log(JSON.stringify({error: error}, replaceErrors));

                if (error.properties && error.properties.errors instanceof Array) {
                    const errorMessages = error.properties.errors.map(function (error) {
                        return error.properties.explanation;
                    }).join("\n");
                    console.log('errorMessages', errorMessages);
                    // errorMessages is a humanly readable message looking like this :
                    // 'The tag beginning with "foobar" is unopened'
                }
                throw error;
            }

            var zip = new PizZip(content);
            var doc;
            try {
                doc=new window.docxtemplater(zip);
            } catch(error) {
                // Catch compilation errors (errors caused by the compilation of the template : misplaced tags)
                errorHandler(error);
            }
            const array = ['John', 'Jane']
            array.forEach(function(name){
              console.log(name);
              doc.setData({
                  first_name: name,
                  last_name: 'Doe',
                  phone: '0652455478',
                  description: 'New Website'
              });

              try {
                // render the document (replace all occurences of {first_name} by John, {last_name} by Doe, ...)
                doc.render();
              }
              catch (error) {
                // Catch rendering errors (errors relating to the rendering of the template : angularParser throws an error)
                errorHandler(error);
              }

              var out=doc.getZip().generate({
                type:"blob",
                mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
              }) //Output the document using Data-URI

              zipDocs.file(name+".docx", out);
              console.log(name, " wurde gezippt.");
          })
          var content = zipDocs.generate({ type: "blob" });

          // see FileSaver.js
          saveAs(content, "example.zip");
        })
    }
    </script>
</html>

The generation of the zip-file fails with the error message:

Uncaught Error: The data of 'John.docx' is in an unsupported format !

I guess that I have to generate a different output but I don't know how.

@timm333 timm333 changed the title Zipping multiple documents in one zipfile failes Zipping multiple documents in one zipfile fails Aug 4, 2020
@edi9999
Copy link
Member

edi9999 commented Aug 4, 2020

Hello @timm333 ,

First, You should not reuse a docxtemplater instance twice.
This means that you should not call doc.setData() twice on a given document.
You have to reconstruct the Pizzip and the docxtemplater instance every time.

As for the error that you get, you can use the following by using generate without any options :

var out=doc.getZip().generate();
zipDocs.file(name+".docx", out);

@edi9999 edi9999 closed this as completed Aug 4, 2020
@timm333
Copy link
Author

timm333 commented Aug 5, 2020

Thanks, I improved the code with your suggestions. This eliminates the error and I get multiple docx in one zip file. But the docx-files don't seem to be valid and I cannot open them. Is this because the generate is without options?

    <body>
        <button onclick="generate()">Generate document</button>
    </body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/docxtemplater/3.17.9/docxtemplater.js"></script>
    <script src="https://unpkg.com/pizzip@3.0.6/dist/pizzip.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.js"></script>
    <script src="https://unpkg.com/pizzip@3.0.6/dist/pizzip-utils.js"></script>

    <script>
    var zipDocs = new PizZip();
    function loadFile(url,callback){
        PizZipUtils.getBinaryContent(url,callback);
    }

    function generate() {

        loadFile("https://docxtemplater.com/tag-example.docx",function(error,content){
            if (error) { throw error };

            // The error object contains additional information when logged with JSON.stringify (it contains a properties object containing all suberrors).
            function replaceErrors(key, value) {
                if (value instanceof Error) {
                    return Object.getOwnPropertyNames(value).reduce(function(error, key) {
                        error[key] = value[key];
                        return error;
                    }, {});
                }
                return value;
            }

            function errorHandler(error) {
                console.log(JSON.stringify({error: error}, replaceErrors));

                if (error.properties && error.properties.errors instanceof Array) {
                    const errorMessages = error.properties.errors.map(function (error) {
                        return error.properties.explanation;
                    }).join("\n");
                    console.log('errorMessages', errorMessages);
                    // errorMessages is a humanly readable message looking like this :
                    // 'The tag beginning with "foobar" is unopened'
                }
                throw error;
            }
            const array = ['John','Jane']
            array.forEach(function(name){
              var zip = new PizZip(content);
              var doc;
              try {
                  doc=new window.docxtemplater(zip);
              } catch(error) {
                  // Catch compilation errors (errors caused by the compilation of the template : misplaced tags)
                  errorHandler(error);
              }
              console.log(name);
              doc.setData({
                  first_name: name,
                  last_name: 'Doe',
                  phone: '0652455478',
                  description: 'New Website'
              });

              try {
                // render the document (replace all occurences of {first_name} by John, {last_name} by Doe, ...)
                doc.render();
              }
              catch (error) {
                // Catch rendering errors (errors relating to the rendering of the template : angularParser throws an error)
                errorHandler(error);
              }

              var out=doc.getZip().generate() //Output the document using Data-URI

              zipDocs.file(name+".docx", out);
              console.log(name, " wurde gezippt.");

          })
          var content = zipDocs.generate({ type: "blob" });
          // see FileSaver.js
          saveAs(content, "example.zip");
        })
    }
    </script>
</html>

@edi9999
Copy link
Member

edi9999 commented Aug 5, 2020

You're right, it works if you do : zipDocs.file(name+".docx", out, {base64: true});

Fully working snippet :

<!DOCTYPE html>
<html lang="en">
    <body>
        <button onclick="generate()">Generate document</button>
    </body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/docxtemplater/3.17.9/docxtemplater.js"></script>
    <script src="https://unpkg.com/pizzip@3.0.6/dist/pizzip.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.js"></script>
    <script src="https://unpkg.com/pizzip@3.0.6/dist/pizzip-utils.js"></script>

    <script>
    var zipDocs = new PizZip();
    function loadFile(url,callback){
        PizZipUtils.getBinaryContent(url,callback);
    }

    function generate() {

        loadFile("https://docxtemplater.com/tag-example.docx",function(error,content){
            if (error) { throw error };

            // The error object contains additional information when logged with JSON.stringify (it contains a properties object containing all suberrors).
            function replaceErrors(key, value) {
                if (value instanceof Error) {
                    return Object.getOwnPropertyNames(value).reduce(function(error, key) {
                        error[key] = value[key];
                        return error;
                    }, {});
                }
                return value;
            }

            function errorHandler(error) {
                console.log(JSON.stringify({error: error}, replaceErrors));

                if (error.properties && error.properties.errors instanceof Array) {
                    const errorMessages = error.properties.errors.map(function (error) {
                        return error.properties.explanation;
                    }).join("\n");
                    console.log('errorMessages', errorMessages);
                    // errorMessages is a humanly readable message looking like this :
                    // 'The tag beginning with "foobar" is unopened'
                }
                throw error;
            }
            const array = ['John','Jane']
            array.forEach(function(name){
              var zip = new PizZip(content);
              var doc;
              try {
                  doc=new window.docxtemplater(zip);
              } catch(error) {
                  // Catch compilation errors (errors caused by the compilation of the template : misplaced tags)
                  errorHandler(error);
              }
              console.log(name);
              doc.setData({
                  first_name: name,
                  last_name: 'Doe',
                  phone: '0652455478',
                  description: 'New Website'
              });

              try {
                // render the document (replace all occurences of {first_name} by John, {last_name} by Doe, ...)
                doc.render();
              }
              catch (error) {
                // Catch rendering errors (errors relating to the rendering of the template : angularParser throws an error)
                errorHandler(error);
              }

              var out=doc.getZip().generate() //Output the document using Data-URI
              zipDocs.file(name+".docx", out, {base64: true});
              console.log(name, " wurde gezippt.");

          })
          var content = zipDocs.generate({ type: "blob" });
          // see FileSaver.js
          saveAs(content, "example.zip");
        })
    }
    </script>
</html>

@timm333
Copy link
Author

timm333 commented Aug 10, 2020

That works perfect. Many thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants