Word addin使用office.js在contentControl中插入带有样式的复杂列表结构吗?

时间:2019-03-15 22:15:47

标签: openxml office-js word-addins word-contentcontrol

我正在尝试使用JavaScript API将复杂的列表结构插入MS Word中的contentControl中。该结构是根据包含嵌套数组的对象构建的:不同的项包含子项,子项包含不同的属性。这些项目数组的大小可以更改,因此需要通用。也许Office.js API并不是真正为我要达到的目的而构建的,我应该使用insertHTML(具有HTML中构建的结构)或OOXML。

This is the structure I already build

产生此功能的函数:

import ContentControl = Word.ContentControl;
import {formatDate} from '../formatters';
let firstItem = true;
let listId;

export async function resolveItems(contentControl: ContentControl, data: Array<any>, t) {
Word.run(  contentControl, async (context) => {
    contentControl.load('paragraphs');
    await context.sync();
    for (const item of data) {
        if (firstItem) {
            const firstPara = contentControl.paragraphs.getFirst();
            firstPara.insertText('ITEM (' + formatDate(item.date) + ')', 'Replace');
            firstItem = false;
            const contactList = firstPara.startNewList();
            contactList.load('id');
            await context.sync().catch((error) => {
                console.log('Error: ' + error);
                if (error instanceof OfficeExtension.Error) {
                    console.log('Debug info: ' + JSON.stringify(error.debugInfo));
                }
            });
            listId = contactList.id;
        } else {
            const otherItem = contentControl.insertParagraph('ITEM (' + formatDate(item.date) + ')', 'End');
            otherItem.load(['isListItem']);
            await context.sync();
            otherItem.attachToList(listId, 0);
        }
        for (const subItem of item.subItems) {
            let descriptionParaList = new Array();
            let subItemPara = contentControl.insertParagraph(subItem.title + ' (' + formatDate(subItem.date) + ')', 'End');
            subItemPara.load(['isListItem']);
            await context.sync();
            if (subItemPara.isListItem) {
                subItemPara.listItem.level = 1;
            } else {
                subItemPara.attachToList(listId, 1);
            }
            let descriptions = subItem.descriptions;
            for (const description of descriptions) {
                let descriptionPara = contentControl.insertParagraph('', 'End');
                descriptionPara.insertText(t(description.descriptionType) + ': ', 'Start').font.set({
                    italic: true
                });
                descriptionPara.insertText(description.description, 'End').font.set({
                    italic: false
                });
                descriptionPara.load(['isListItem', 'leftIndent']);
                descriptionParaList.push(descriptionPara);
            }
            await context.sync();
            for (const subItemPara of descriptionParaList) {
                if (subItemPara.isListItem) {
                    subItemPara.detachFromList();
                }
                subItemPara.leftIndent = 72;
            }

        }
    }
    return context.sync().catch((error) => {
        console.log('Error: ' + error);
        if (error instanceof OfficeExtension.Error) {
            console.log('Debug info: ' + JSON.stringify(error.debugInfo));
        }
    });
});}

数据结构如下:

'LAST_5_Items': [
    {
        'date': '2019-03-14T14:51:29.506+01:00',
        'type': 'ITEM',
        'subItems': [
            {
                'date': '2019-03-14T14:51:29.506+01:00',
                'title': 'SUBITEM 1',
                'descriptions': [
                    {
                        'descriptionType': 'REASON',
                        'description': 'Reason 1',
                        'additionalInformation': ''
                    }
                ]
            },
            {
                'date': '2019-03-14T14:51:29.506+01:00',
                'title': 'SUBITEM 2',
                'descriptions': [
                    {
                        'descriptionType': 'REASON',
                        'description': 'Reason 1',
                        'additionalInformation': ''
                    }
                ]
            }
        ]
    },
    {
        'date': '2019-03-14T14:16:26.220+01:00',
        'type': 'ITEM',
        'subItems': [
            {
                'date': '2019-03-14T14:16:26.220+01:00',
                'title': 'SUBITEM 1',
                'descriptions': [
                    {
                        'descriptionType': 'REASON',
                        'description': 'Reason 1',
                        'additionalInformation': ''
                    }
                ]
            },
            {
                'date': '2019-03-14T14:16:26.220+01:00',
                'title': 'SUBITEM 2',
                'descriptions': [
                    {
                        'descriptionType': 'REASON',
                        'description': 'Reason 1',
                        'additionalInformation': ''
                    },
                    {
                        'descriptionType': 'SUBJECTIVE',
                        'description': 'Subjective 1',
                        'additionalInformation': ''
                    },
                    {
                        'descriptionType': 'SUBJECTIVE',
                        'description': 'Subjective 2',
                        'additionalInformation': ''
                    },
                    {
                        'descriptionType': 'OBJECTIVE',
                        'description': 'Objective 1',
                        'additionalInformation': ''
                    },
                    {
                        'descriptionType': 'OBJECTIVE',
                        'description': 'Objective 2',
                        'additionalInformation': ''
                    },
                    {
                        'descriptionType': 'EVALUATION',
                        'description': 'Evaluation',
                        'additionalInformation': ''
                    },
                    {
                        'descriptionType': 'REASON',
                        'description': 'Reason 1',
                        'additionalInformation': ''
                    }
                ]
            }
        ]
    }
]

我要实现的是模板解析器。该插件将允许用户在文档中放置占位符(ContentControls),标签(例如名字,姓氏...)和最后5个联系人(我现在正在描述的联系人),当他解析文件时,它将获取所有所需的数据,并开始使用此结构化布局替换ContentControls。

是的,代码可以工作,但是我非常怀疑代码的结构是否经过这么多的context.sync()调用。速度太慢,无法使用。 我需要这么多context.sync(),因为我需要列表ID的属性以及一个段落是否属于列表。 有没有更好的方法可以使用office.js API实现我要实现的目标?

理想情况下,队列应该同步一次,这样用户就不会像现在那样以奇怪的方式看到正在添加和更改的内容。

谢谢

1 个答案:

答案 0 :(得分:0)

有一种避免将context.sync放入循环中的技术。基本思想是您有两个循环,它们之间有一个context.sync。在第一个循环中,创建一个对象数组。每个对象都包含对要处理的Office对象之一的引用(例如,更改,删除等)。但是对象具有其他属性。他们每个人都拥有处理该对象所需的某些数据。这些其他项目可以是其他Office对象的属性,也可以是其他数据。另外,在循环中或循环之后,您load context.sync数组对象中所有Office对象所需的所有属性。 (这通常在循环内更容易执行。)

然后您有context.sync

同步之后,您将遍历在str.split()之前创建的对象数组。第二个循环中的代码使用您创建的对象的其他属性处理每个对象(您要处理的Office对象)中的第一项。

以下是此技术的几个示例:

我对这个StackOverflow问题的回答:Document not in sync after replace text

此代码示例: https://github.com/OfficeDev/Word-Add-in-Angular2-StyleChecker/blob/master/app/services/word-document/word.document.service.js