Word 插件使用 office.js 在 contentControl 中插入具有样式的复杂列表结构完成与否?
Word addin inserting complex list structure with styling in a contentControl using office.js done or not?
我正在尝试使用 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?
理想情况下,队列应该同步一次,这样用户就不会看到以一种非常奇怪的方式添加和更改的内容,就像现在的行为一样。
谢谢
有一种技术可以避免在循环中出现 context.sync
。基本思想是你有两个循环,它们之间有一个 context.sync
。在第一个循环中,您创建了一个对象数组。每个对象都包含对您要处理的 Office 对象之一的引用(例如,更改、删除等)。它看起来像您案例中的段落。但是该对象具有其他属性。它们中的每一个都包含处理对象所需的一些数据项。这些其他项目可能是其他 Office 对象的属性,也可能是其他数据。此外,无论是在循环中还是在循环之后,您 load
都需要数组中对象中所有 Office 对象的所有属性。 (这通常在循环内更容易完成。)
那么你有 context.sync
.
同步后,您将遍历在 context.sync
之前创建的对象数组。第二个循环中的代码使用您创建的对象的其他属性处理每个对象(即您要处理的 Office 对象)中的第一项。
以下是此技术的几个示例:
我对这个 Whosebug 问题的回答:。
我正在尝试使用 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?
理想情况下,队列应该同步一次,这样用户就不会看到以一种非常奇怪的方式添加和更改的内容,就像现在的行为一样。
谢谢
有一种技术可以避免在循环中出现 context.sync
。基本思想是你有两个循环,它们之间有一个 context.sync
。在第一个循环中,您创建了一个对象数组。每个对象都包含对您要处理的 Office 对象之一的引用(例如,更改、删除等)。它看起来像您案例中的段落。但是该对象具有其他属性。它们中的每一个都包含处理对象所需的一些数据项。这些其他项目可能是其他 Office 对象的属性,也可能是其他数据。此外,无论是在循环中还是在循环之后,您 load
都需要数组中对象中所有 Office 对象的所有属性。 (这通常在循环内更容易完成。)
那么你有 context.sync
.
同步后,您将遍历在 context.sync
之前创建的对象数组。第二个循环中的代码使用您创建的对象的其他属性处理每个对象(即您要处理的 Office 对象)中的第一项。
以下是此技术的几个示例:
我对这个 Whosebug 问题的回答: