You are currently offline, serving cached version

Usage

There are two ways of using the slides module. Explicit, where the developper specifies which slides to repeat, and Tagging, where the template creator chooses which slides to repeat from the template itself by tagging slides with a specific tag.

After installing the module, you can use a working demo by running node sample.js.

Explicit

If you use the explicit method, you write from the code which slides you want to repeat :

const SlidesModule = require("docxtemplater-slides-module");

const slidesModule = new SlidesModule();

const data = {
    slides: [
        {
            $slide: 1,
            name: "Franck",
            phone: "+665432131",
        },
        {
            $slide: 1,
            name: "Jim",
            phone: "+6234468468",
        },
        {
            $slide: 1,
            name: "Joe",
            phone: "+78788787",
        },
        {
            $slide: 1,
            name: "Hugh",
            phone: "03566456465",
        },
        { $slide: 3, title: "The Title" },
        {
            $slide: 2,
            content:
                "Lorem ipsum dolor sit amet, consectetur adipisicing elit...",
        },
    ],
};

const doc = new Docxtemplater(zip, {
    modules: [slidesModule],
});
doc.render(data);

const buffer = doc.getZip().generate({
    type: "nodebuffer",
    compression: "DEFLATE",
});

fs.writeFile("test.docx", buffer);

And in your template, write :

Slide1
------

{name} {phone}

Slide 2
-------

{content}

Slide 3
-------

{title}

This means that : you want to use the \$slide 1 from the template to generate 4 slides in your output document, then you want to use the slide 3 of your template and put it at position 5 in your output, and use the slide 2 of your template to put it at position 6 in your output. All generated slides also have different data (name, phone, title and content in this example).

With the explicit method, it is possible to reorder slides, duplicate them or remove them.

Tagging

In that case, it is the template creator that will tag certain slides to express that some slides must be repeated or removed depending on conditions or loops.

To tag a slide with the text "users", you write {:users} anywhere on that slide. Those tags will be removed after generation by docxtemplater.

All slides that are untagged are shown exactly once.

All slides that are tagged are shown depending on the value of the tag.

If the value is an array, the slide is repeated for each element in an array.

If the value is false or falsy, the slide is removed.

If the value is true or truthy, the slide is shown once.

const SlidesModule = require("docxtemplater-slides-module");

const slidesModule = new SlidesModule();

const data = {
    mainTitle: "My title",
    users: [
        { name: "Franck", phone: "+665432131" },
        { name: "Jim", phone: "+6234468468" },
        { name: "Joe", phone: "+78788787" },
        { name: "Hugh", phone: "03566456465" },
    ],
    foo: "bar",
};

const doc = new Docxtemplater(zip, {
    modules: [slidesModule],
});
doc.render(data);

const buffer = doc.getZip().generate({
    type: "nodebuffer",
    compression: "DEFLATE",
});

fs.writeFile("test.docx", buffer);

And in your template, write :

Slide1
------

{mainTitle}
Slide2
------

{:users}
{name} {phone}

In this case, the first slide will be shown once, and the second slide will be repeated 4 times (since users is an array of 4 elements).

With the slides module and the tagging "mode", it is possible to remove slides conditionnally. To do that, you have to tag the slide with the text {:isShown} and set {isShown:false} in your render(data) call.

Usage (browser)

<html>
    <script src="node_modules/docxtemplater/build/docxtemplater.js"></script>
    <script src="node_modules/pizzip/dist/pizzip.js"></script>
    <script src="node_modules/pizzip/vendor/FileSaver.js"></script>
    <script src="node_modules/pizzip/dist/pizzip-utils.js"></script>
    <script src="build/slides-module.js"></script>
    <script>
        PizZipUtils.getBinaryContent(
            "demo_template.pptx",
            function (error, content) {
                if (error) {
                    console.error(error);
                    return;
                }
                var slidesModule =
                    new DocxtemplaterSlidesModule();

                var zip = new PizZip(content);
                var doc = new docxtemplater(zip, {
                    modules: [slidesModule],
                });

                doc.render({
                    date: "02-25-2018",
                    title: "My presentation",
                    description: "A wonderful card",
                    users: [
                        { name: "John Doe" },
                        { name: "Jane Zang" },
                        { name: "Mary Bar" },
                    ],
                });

                var out = doc.getZip().generate({
                    type: "blob",
                    mimeType:
                        "application/vnd.openxmlformats-officedocument.presentationml.presentation",
                });
                saveAs(out, "generated.pptx");
            }
        );
    </script>
</html>

Special Features

Everything that is outside of the "slides" key is automatically accessible from all templated slides.

You can use the special variables {$count} and {$index} in your template to get the index of the current slide, and the total count of the slides (in the expected output).

FAQ

Is it possible to manipulate slides within a presentation ?

Yes, either with the explicit method or the tagging method explained above.

Is it possible to reorder slides ?

Yes, with the explicit method that is possible. It is however not possible with the tagging method, since tagging will keep the same order of the slides as in the template document.

Is it possible to combine two presentations from two pptx files ?

This is possible with the pptx-subtemplate module.

Is it possible to get a JSON representation of the slides ?

Yes, you can do the following to get a JSON data structure :

const zip = new PizZip(content);
const SlidesModule = require("docxtemplater-slides-module");
const slidesModule = new SlidesModule();
const doc = new Docxtemplater(zip, {
    modules: [slidesModule],
});
console.log(
    require("util").inspect(this.doc.compiled, {
        showHidden: true,
        depth: 2,
    })
);

it gives you following JSON object :

{
    "ppt/slides/slide1.xml": {
        "content": "<?xml......"
    },
    "ppt/slides/slide2.xml": {
        "content": "<?xml......"
    }
}

Is it possible to loop recursively on multiple elements to generate slides ?

If your data structure is the following :

data = {
    companies: [
        {
            name: "Ecorp",
            user: [
                { name: "John", salary: 20000 },
                { name: "Mary", salary: 25000 },
                { name: "Steve", salary: 30000 },
            ],
        },
        {
            name: "Fcorp",
            user: [
                { name: "Paul", salary: 45000 },
                { name: "Dominique", salary: 40000 },
            ],
        },
    ],
};

And you would like to create one slide for each user, and be able to access the company name as well as the user name, than you could use the recur filter I created.

In your template, you can then write :

{:this | recur:"companies/company":"user"}
{company.name} => will return Ecorp/Fcorp
{user.name} => will return John/Mary/Steve/Paul/Dominique

Here's the code sample with the recur filter :

const SlidesModule = require("docxtemplater-slides-module");
const expressions = require("angular-expressions");
const assign = require("lodash/assign");
const merge = require("lodash/merge");
expressions.filters.recur = function (input, ...items) {
    if (!input) {
        return input;
    }
    let result = [merge({}, input)];
    items.forEach(function (item) {
        const splitted = item.split("/");
        const loopOver = splitted[0];
        const name = splitted[1] || loopOver;
        const newResult = [];
        result.forEach(function (r) {
            r[loopOver].forEach(function (a) {
                const obj = {};
                obj[name] = a;
                newResult.push(merge({}, r, obj, a));
            });
        });
        result = newResult;
    });
    return result;
};
function angularParser(tag) {
    if (tag === ".") {
        return {
            get: function (s) {
                return s;
            },
        };
    }
    const expr = expressions.compile(
        tag.replace(/(’|‘)/g, "'").replace(/(“|”)/g, '"')
    );
    return {
        get: function (scope, context) {
            let obj = {};
            const scopeList = context.scopeList;
            const num = context.num;
            for (let i = 0, len = num + 1; i < len; i++) {
                obj = assign(obj, scopeList[i]);
            }
            return expr(scope, obj);
        },
    };
}
new Docxtemplater(zip, {
    parser: angularParser,
    modules: [new SlidesModule()],
});

CHANGELOG

3.4.0

Correctly remove notesSlides and notesSlides rels in ContentTypes

Make module compatible with docxtemplater@3.28.0. Please make sure to update docxtemplater to 3.28.0 at the same time you update this module. The internal change made is the use of the new matchers API which fixes bugs that were triggered depending on the order of the modules that are attached to the instance. Now the order of the modules should not matter as expected.

3.3.7

Bugfix Cannot read properties of undefined (reading 'Index of') when using slides module in async mode and having internal {#loop} tag inside the slide.

Fixes : https://github.com/open-xml-templating/docxtemplater/issues/628

3.3.6

Bugfix to avoid corruption when looping over slide that has a chart

3.3.5

Bugfix to avoid corruption of notesSlides because the rId was incorrect

3.3.4

Use @xmldom/xmldom instead of xmldom, see this github issue

3.3.3

Generate files in built with correct filename In previous versions, the filename was always build/docxtemplater.js. Now the filename is error-location-module.js The .min.js file is also created now.

3.3.2

Do not fail when using multiple {:tags} in separate slides in titles.

The error that was thrown by mistake was :

properties: {
    explanation: 'The slide NaN has multiple {:tags}, which is not allowed on a single slide',
    id: 'slide_has_multiple_tags',
    tags: [ [Object], [Object] ],
    slide: NaN,
    file: 'docProps/app.xml'
}

This fixes the bug reported here.

3.3.1

Add typescript definitions for public API

3.3.0

Throw error when multiple {:tags} are on one single slide.

If you want to loop recursively on multiple elements, I recommend you to use the "recur" filter, documented here.

3.2.12

Require docxtemplater version 3.22.0

Bugfixes issue when using module asynchronously, where the output would not wait for the promises to be resolved and show '[object Promise]' in the generated document

3.2.11

Create a subscope when looping over a slide tag, such as {:users}.

This way, it is possible to retrieve parent properties even if they would be overwritten by the loop.

For example for the following data

{
    "name": "John",
    "users": [
        {
            "name": "Mary"
        }
    ]
}

when using {:users}

3.2.10

Add {part} when calling the parser from the slides module.

This will fix an issue of data.meta.part not being defined when used in your custom parser.

3.2.9

Bugfix use real scopeManager for getting value of {:foo | bar} to be calling parser with the same parameters as when using the parser.

If you are using the code with following parser, you will have the error "Cannot read property scopeList of undefined", because the variable "context" was not passed.

return {
    get: function (scope, context) {
        let obj = {};
        const scopeList = context.scopeList;
        const num = context.num;
        for (let i = 0, len = num + 1; i < len; i++) {
            obj = merge(obj, scopeList[i]);
        }
        return expr(scope, obj);
    },
};

3.2.8

Run parser passed to Docxtemplater options object for tags in slides explicit module.

For example, it is now possible to use angular expressions in slide tags, for example :

{:users | ifActive} if you define the expressions.filters.ifActive

3.2.7

A bug was introduced in version 3.2.2 which would, after 1000s of generations, trigger a Maximum call stack size exceeded. This release fixes the bug.

3.2.6

Bugfix do not fail with Cannot read property 'setAttribute' of undefined at js/slidesrepo.js:19:2 when having a slide note without a reference to the slide.

3.2.5

Declare supportedFileTypes, which allows to use this module with the new docxtemplater constructor which was introduced in docxtemplater 3.17.

3.2.4

Bugfix to work together with pptx-subtemplate module, previous versions could produce corrupt documents

3.2.3

Make it possible to use together with pptx-subtemplate module

3.2.2

Add templating on notes of each slides

3.2.1

Bugfix when the targets of the presentation.xml are absolute path instead of relative paths

3.2.0

  • Add support for chunking (it is used currently only in the table module for the "grid" feature.

3.1.9

  • Update browser build to use XMLSerializer instead of xmldom

  • Use requiredAPIVersion

3.1.8

  • Move docxtemplater from devDependencies to dependencies

Explanation : On some versions of npm (notably 5.8.0), when having a package containing docxtemplater-slides-module, the installation will generate a tree of node_modules that puts the module on a level where it has no access to docxtemplater. By explicitly asking it as a dependency, this issue is avoided.

3.1.7

Fix bug of notes being "moved" from one slide to the other during generation

3.1.6

Include notes for each of the rendered slide

3.1.5

Fail properly when a slide does not exist

3.1.4

Add support for boolean values true/false and objects in loops

3.1.3

Bugfix : SlideMasters are now correctly templated

3.1.2

Bugfix when having notes in pptx

3.1.1

Bugfix : Slide 10 and following slides are no longer removed

3.1.0

Add possibility to tag slides for repetition with {:users}

3.0.3

Add compatibility with image-module

3.0.2

Exported files are now ES5

3.0.1

Bugfix : Slides module doesn't throw an error anymore when templating docx files

3.0.0

Initial release