You are currently offline, serving cached version
10 December 2024 : If you are using angular-expressions to parse expressions such as {user.name}, {#users.length > 10}, please upgrade asap to angular-expressions@1.4.3 for security reasons : View Github issue

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 fs = require("fs");

const doc = new Docxtemplater(zip, {
    modules: [new SlidesModule()],
});
doc.render({
    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 buffer = doc.getZip().generate({
    type: "nodebuffer",
    compression: "DEFLATE",
});

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

And in your template, write :

{name} {phone}

{content}

{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 fs = require("fs");
const SlidesModule = require("docxtemplater-slides-module");

const doc = new Docxtemplater(zip, {
    modules: [new SlidesModule()],
});
doc.render({
    mainTitle: "My title",
    users: [
        { name: "Franck", phone: "+665432131" },
        { name: "Jim", phone: "+6234468468" },
        { name: "Joe", phone: "+78788787" },
        { name: "Hugh", phone: "03566456465" },
    ],
    foo: "bar",
});

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

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

And in your template, write :

{mainTitle}

{: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;
                }
                const slidesModule =
                    new DocxtemplaterSlidesModule();

                const zip = new PizZip(content);
                const 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" },
                    ],
                });

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

Looping over multiple slides

It is possible to loop over multiple slides using a single {:companies} tag that you place on the slide section part which contains multiple slides.

That section part will be repeated multiple times, and the title of each section will also be templated, meaning you can write as the section name : {:companies}Company {name} to create multiple sections called "Company ECorp", "Company Acme", …

This section for example if you want to create 3 slides for each company, the first slide would be for the company logo and name, the second slide for the company business results, and the third for the objectives of that company.

Template with sections
Template with sections

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 SlidesModule = require("docxtemplater-slides-module");
const doc = new Docxtemplater(zip, {
    modules: [new SlidesModule()],
});
console.log(
    require("util").inspect(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: "Fcorp",
            user: [{ name: "Paul", salary: 45000 }],
        },
    ],
};

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} {user.name}

Which will render the following output :

Ecorp John

Ecorp Mary

Fcorp Paul

Here's the code sample with the recur filter :

const SlidesModule = require("docxtemplater-slides-module");
const assign = require("lodash/assign.js");
const expressionParser = require("docxtemplater/expressions.js");

expressionParser.filters.recur = function (input, ...items) {
    if (!input) {
        return input;
    }
    let newResult = [input];
    items.forEach(function (item) {
        const splitted = item.split("/");
        const loopOver = splitted[0];
        const name = splitted[1] || loopOver;
        const nR = [];
        newResult.forEach(function (r) {
            r[loopOver].forEach(function (a) {
                const obj = {};
                obj[name] = a;
                nR.push(assign({}, r, obj, a));
            });
        });
        newResult = nR;
    });
    return newResult;
};
const doc = new Docxtemplater(zip, {
    parser: expressionParser,
    modules: [new SlidesModule()],
});
doc.render(data);

CHANGELOG

3.6.1

Bugfix when used together with the pptx-subtemplate module

3.6.0

Add support for looping over slide sections.

3.5.6

Make it possible to use prefix from the constructor

3.5.5

Add typescript typings to be able to change the module prefix

3.5.4

Upgrade module to use NodeNext moduleResolution setting. See explanation here

3.5.3

Bugfix to make module work when used together with docxtemplater 3.42.0 and above.

3.5.2

Set module.priority in order to have no more issues related to module ordering

3.5.1

Add module.clone() internal

3.5.0

When templating a file that contains slide sections (groups of slides that have a name), the sections are now properly kept.

3.4.11

Bugfix of 3.4.10 :

The getStructuredTags and other inspect module functions were working only when calling .render(), thus needing to pass in data.

Now, the .getStructuredTags() returns the correct result even without calling .render().

3.4.10

In powerpoint, the inspect module will now return correctly for the getAllTags and getStructuredTags methods :

For this to work, you need to install version 3.37.13 of docxtemplater core or above.

For following template with the slides module attached :

{:loop}
{$index}{name}

The output of inspectModule.getAllTags() will now be :

{
    loop: {
        $index: {},
        name: {},
    }
}

3.4.9

It is now possible to use two dimensional arrays with the slides module.

For example :

{:companies}

{#.}
{.}
{/}

With following data :

doc.render({
    companies: [
        ["Foo", "Bar", "Qux"],
        ["Bang", "Zing"],
    ],
});

3.4.8

If you use the key data "slides", it usually means that you want to tag your slides explicitly.

Since version 3.4.8, if you pass in a slides key which has not the following shape :

doc.render({
    slides: [{ $slide: 2, name: "John" }],
});

If for example you write the following :

doc.render({
    slides: [{ name: "John" }],
});

It will not do any explicit tagging, since the $slide is missing.

This avoids a stacktrace that was complex to understand.

The previous error message was :

Adding slide from null slide undefined

3.4.7

Bugfix to make {$index} work correctly with docxtemplater 3.37.0

3.4.6

Bugfix Cannot read properties of null (reading 'asUint8Array') when using a pptx file that has a chart that contains data from an external file (TargetMode="External").

3.4.5

Requires module api version 3.34.0 or more.

Update to make it possible to use {$index} to know which index we are in a slide loop, like {:slides}

3.4.4

Avoid possible issue of "Maximum call stack size exceeded"

3.4.3

When using together with the table grid module, it is now possible to prechunk the data, so that if you want to put just 2 elements on one slide, and 6 on all other slides, and 3 on one specific other, it is now possible.

The chunking mechanism will now work either with unidimensional arrays, such as :

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

or with nested, two dimensional arrays, such as :

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

This way, the "Doe" name will be put in a separate chunk, even if the chunk size is 3 for example.

3.4.2

Avoid stacktrace when using empty data

3.4.1

Make package size smaller

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 : Github Issue #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 build/slides-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.

const assign = require("lodash/assign.js");
const angularExpressions = require("angular-expressions");
const SlidesModule = require("docxtemplater-slides-module");

function parser(tag) {
    const expr = angularExpressions.compile(tag);
    return {
        get(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);
        },
    };
}

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

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

Talk with sales Contact us