Environment:
Product: ONLYOFFICE Docs (online editor) embedded in a Vue frontend
Integration: Using DocsAPI.DocEditor and editor.createConnector().callCommand(…)
Document type: docx
Use case: composing a “combined report” from multiple child Word templates
Goal:
On the frontend, load several child Word templates and merge them into one document.
Requirement: each child template should ideally start on a new page (or at least in a separate section) without unexpected blank pages.
Current implementation (simplified):
For each child template:
Open it in a hidden DocsAPI.DocEditor.
In onDocumentReady of the hidden editor, call:
const doc = Api.GetDocument();
const json = doc.ToJSON(true, true, true, true, true, true);
Store this JSON as jsonData.
In the main editor:
On main onDocumentReady, create a connector:
this.connector = this.editor.createConnector();
For each child template (in order), insert its JSON block at the end of the current document:
insertJSON(data, index) {
return new Promise((resolve) => {
Asc.scope.toJsonData = typeof data === ‘string’ ? data : JSON.stringify(data);
Asc.scope.templateIndex = index;
this.connector.callCommand(() => {
const doc = Api.GetDocument();
const range = doc.GetRange();
if (range && typeof range.SetEnd === ‘function’) {
range.SetEnd(doc, true); // move caret to document end
}
const jsonBlock = Api.FromJSON(Asc.scope.toJsonData);
const ret = doc.InsertContent(jsonBlock);
Api.Save();
return true;
}, () => resolve());
});
}
We log all key calls (Api.GetDocument, FromJSON, InsertContent, CreateSection, etc.) and we use await and our own runCommand(fn) wrapper to ensure strict sequential execution in JavaScript (no overlapping callCommand).
Experiments with sections / pagination:
We tried several approaches before/after InsertContent:
Api.CreateParagraph, AddPageBreak (earlier tests).
doc.CreateSection(paragraph) with different paragraph anchors.
Moving the range with doc.GetRange().SetEnd(doc, true).
The current experimental flow is:
Insert template 1 (JSON) at the end using FromJSON + InsertContent.
Immediately after template 1 insertion finishes, we run a section + anchor command:
await runCommand(() => {
const doc = Api.GetDocument();
let lastIndex = doc.GetElementsCount && doc.GetElementsCount()
? doc.GetElementsCount() - 1
: -1;
let paragraph = lastIndex >= 0 && doc.GetElement
? doc.GetElement(lastIndex)
: null;
if (!paragraph) {
paragraph = Api.CreateParagraph();
}
paragraph.AddText && paragraph.AddText(‘Section Anchor Test’);
const section = doc.CreateSection(paragraph);
if (section) {
section.SetEqualColumns(1, 720);
section.SetPageSize(12240, 15840);
section.SetPageMargins(1440, 1440, 1440, 1440);
section.SetHeaderDistance(720);
section.SetFooterDistance(576);
}
const simplePara = Api.CreateParagraph();
if (simplePara) {
simplePara.AddText && simplePara.AddText(‘Section Anchor Test – After Section’);
doc.Push(simplePara);
}
return true;
});
Then we move the caret to the end again:
await runCommand(() => {
const doc = Api.GetDocument();
const range = doc.GetRange();
if (range && typeof range.SetEnd === ‘function’) {
range.SetEnd(doc, true);
}
return true;
});
Finally, we insert template 2 (JSON) using the same insertJSON logic (FromJSON + InsertContent).
We verified via detailed logs that the execution order is strictly:
Insert template 1 JSON
Run CreateSection + Push(simplePara)
Move range to end
Insert template 2 JSON
There is no parallelism at the JavaScript level.
Observed behavior:
If we compose only template 1 + the section anchor paragraph (template 2 not inserted), pagination looks correct: template 1 content, then the anchor text in the expected place (often at the start of a new page).
As soon as we insert template 2 using FromJSON + doc.InsertContent(jsonBlock):
Template 1 and template 2 content appear directly one after another (on the same continuous flow/pages).
The section anchor paragraph (‘Section Anchor Test’ and ‘Section Anchor Test – After Section’) is moved to the end of the document, after both templates.
In earlier experiments, we also saw extra blank pages being introduced depending on the child template content.
This suggests that when we insert a full document JSON block from a child template, OnlyOffice’s layout/section engine recalculates or merges section structures and does not respect the “manual” section we created between template 1 and template 2. The final pagination and section boundaries appear to be dominated by the internals of FromJSON + InsertContent, not by the explicit CreateSection calls we make in front-end code.
What we already tried / ruled out:
Ensured strict sequential execution with:
await insertJSON(…) for each template;
await runCommand(…) for the section commands and for range.SetEnd.
Various combinations of:
Creating the paragraph first and then calling doc.CreateSection(paragraph) (exactly like the official sample);
Pushing the paragraph before/after CreateSection;
Moving the range before/after inserting JSON or creating sections.
Isolating the behavior:
With only template 1 + section: section/anchor appears where expected.
With template 1 + section + template 2: the section/anchor ends up after both templates, and we cannot reliably get “template 2 starts on a new page” behavior.
Question to OnlyOffice team:
Is this behavior expected when using Api.FromJSON(…) and doc.InsertContent(…) to merge multiple documents?
Does OnlyOffice intentionally reflow/merge section structures from the inserted JSON so that manually created sections in the “host document” cannot reliably control where the inserted content starts?
Is there any recommended API pattern on the JavaScript side to:
Insert a second document (template 2) after template 1’s content, and
Guarantee that template 2 starts at least in a new section / on a new page,
Without the section/anchor being moved behind the inserted JSON?
If this cannot be reliably achieved via the front-end JS API (connector + FromJSON/InsertContent), is the official recommendation to:
Perform document-level composition on the server side (e.g., with Document Builder or another SDK),
Insert proper next-page section breaks at DOCX level,
And then open only the final merged document in the browser?
Finally, is there any documented limitation or best practice regarding use of ToJSON/FromJSON for cross-document composition, especially around sections and pagination?
Any guidance, example code, or clarification of limitations would be very helpful. Our main objective is to know whether this “per-template new page/section” layout can be reliably implemented in the browser using the current OnlyOffice JavaScript API, or whether we should move this logic to a backend document-processing step.