You are currently offline, serving cached version

Slides Module

This module makes it possible to create multiple slides with a loop in a pptx. For example, you could clone slides for each of your products. The whole order of the slides can be declared from the data.

This module is available as part of the docxtemplater PRO plan.

Installation

You will need docxtemplater v3: npm install docxtemplater

Install this module with npm install --save "$url"

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.setData(data).render();

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} anywher 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.setData(data).render();

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 setData() 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.setData({
                    date: "02-25-2018",
                    title: "My presentation",
                    description: "A wonderful card",
                    users: [
                        { name: "John Doe" },
                        { name: "Jane Zang" },
                        { name: "Mary Bar" },
                    ],
                });

                doc.render();
                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 ?

No, this is currently not possible, but could be implemented, contact me if you're interested.

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.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

I'm the creator of docxtemplater. I work on making docxtemplater great since 2013.