{
  "$schema": "https://ai.syncfusion.com/schema/registry-item.json",
  "name": "docx-editor-mail-merge",
  "framework": "vue",
  "type": "registry:component",
  "component": "DocxEditor",
  "variant": "mail-merge",
  "dependencies": [
    "@syncfusion/ej2-vue-buttons",
    "@syncfusion/ej2-vue-documenteditor",
    "@syncfusion/ej2-vue-lists",
    "@syncfusion/ej2-vue-popups",
    "@syncfusion/ej2-vue-splitbuttons"
  ],
  "description": "Word document editor with mail-merge fields, insert-field dialog, and merge toolbar.",
  "meta": {
    "essentialStudioRelease": "2026 Volume 2 (v34.1.29)",
    "license": "commercial-or-community",
    "licenseNote": "The Syncfusion package is licensed. The composition in this file is source you own and edit. See https://ai.syncfusion.com/licensing.md",
    "requiresLicenseKey": true,
    "requiresServerEndpoint": true,
    "platformIndex": "https://ai.syncfusion.com/vue/llms.txt",
    "skillPack": "syncfusion/vue-ui-components-skills",
    "docs": "https://ai.syncfusion.com/gallery/vue/docx-editor-mail-merge.md"
  },
  "files": [
    {
      "target": "src/components/docx-editor-mail-merge/DocxEditor.vue",
      "content": "<template>\n<div class='control-pane'>\n<div class=\"control-section\">\n  \n   \n        <div class=\"default-section\">\n          <div ref=\"de_titlebar\" id=\"documenteditor_titlebar\" class=\"e-de-ctn-title\">\n    <div v-on:keydown=\"titleBarKeydownEvent\" v-on:click=\"titleBarClickEvent\" class=\"single-line\" id=\"documenteditor_title_contentEditor\" title=\"Document Name. Click or tap to rename this document.\" contenteditable=\"false\">\n        <label v-on:blur=\"titleBarBlurEvent\" id=\"documenteditor_title_name\" :style=\"titileStyle\" >{{documentName}}</label>\n    </div>    \n    <ejs-button id=\"de-print\" :style=\"iconStyle\" :iconCss=\"printIconCss\" v-on:click=\"printBtnClick\" title=\"Print this document (Ctrl+P).\">Print</ejs-button>\t\n    <ejs-dropdownbutton ref=\"de-export\" :style=\"iconStyle\" :items=\"exportItems\" :iconCss=\"exportIconCss\" cssClass=\"e-caret-hide\" content=\"Download\" v-bind:select=\"onExport\" :open=\"openExportDropDown\" title=\"Download this document.\"></ejs-dropdownbutton>        \n</div>\n<div style=\"display: flex; flex-direction: row;\">\n<div class=\"col-lg-2 control-section\" style=\"padding-right: inherit;padding-top:5px;padding-left: 5px;height: 600px;border-left: 1px solid rgb(238, 238, 238);border-bottom:  1px solid rgb(238, 238, 238);\" >\n                    <b><label style=\"display:block;margin:1px;padding-top: 18px;font-size: 14px;padding-top: 5px\">Select Field to Insert</label></b>\n                    <ejs-listview id='de-flat-list' :dataSource='listData' :fields='fields' :select=\"onselect\"></ejs-listview>\n                </div>\n                <div class=\"col-lg-10 control-section\" style='padding-left: 0px;padding-right: 0px;padding-top: 0px;' >\n<ejs-documenteditorcontainer id=\"container\" ref=\"doceditcontainer\" :serviceUrl=\"hostUrl\" :enableToolbar='true' height='600px' :toolbarClick='clickHandler'>\n     <ejs-dialog ref=\"accessDialog\" :header='header' :width='width' :height='height' :showCloseIcon='true'  :buttons='buttons' :content='content'>\n        </ejs-dialog></ejs-documenteditorcontainer>  \n                </div>\n                </div>            \n        </div>\n    </div>\n     <div class=\"overlay\" id=\"popup-overlay\"></div>\n            <div id='waiting-popup' >\n                <svg class=\"circular\" height=\"40\" width=\"40\">\n                    <circle className=\"circle-path\" cx=\"25\" cy=\"25\" r=\"20\" fill=\"none\" stroke-width=\"6\" stroke-miterlimit=\"10\" />\n                </svg>\n            </div>\n</div>\n</template>\n<script>\nimport { DocumentEditorContainerComponent, Toolbar } from \"@syncfusion/ej2-vue-documenteditor\";\nimport { DropDownButtonComponent } from \"@syncfusion/ej2-vue-splitbuttons\";\nimport { DialogComponent } from '@syncfusion/ej2-vue-popups';\nimport { ButtonComponent } from '@syncfusion/ej2-vue-buttons';\nimport { Dialog } from '@syncfusion/ej2-popups';\nimport { ListViewComponent } from \"@syncfusion/ej2-vue-lists\";\nimport { Draggable, Droppable } from '@syncfusion/ej2-base';\n\nexport default {\n    components: {\n        'ejs-documenteditorcontainer': DocumentEditorContainerComponent,\n        'ejs-dropdownbutton': DropDownButtonComponent,\n        'ejs-button': ButtonComponent,\n        'ejs-dialog': DialogComponent,\n        'ejs-listview': ListViewComponent\n    },\n    data: function() {\n        return {\n          hostUrl : 'https://document.syncfusion.com/web-services/docx-editor/api/documenteditor/',\n          documentName : 'Mail Merge',\n          documentTitle: 'Untitled Document',\n          iconStyle: 'float:right;background: transparent;box-shadow:none;border-color: transparent;border-radius: 2px;color:inherit;font-size:12px;text-transform:capitalize;margin-top:4px;height:28px;font-weight:400;font-family:inherit;',\n            titileStyle: 'text-transform:capitalize;font-weight:400;font-family:inherit;text-overflow:ellipsis;white-space:pre;overflow:hidden;user-select:none;cursor:text',\n            openIconCss: 'e-de-icon-Open e-de-padding-right',\n            printIconCss: 'e-de-icon-Print e-de-padding-right',\n            exportIconCss: 'e-de-icon-Download e-de-padding-right',\n            exportItems: [\n                { text: 'Syncfusion Document Text (*.sfdt)', id: 'sfdt' },\n                { text: 'Word Document (*.docx)', id: 'word' },\n                { text: 'Word Template (*.dotx)', id: 'dotx' },\n                { text: 'Plain Text (*.txt)', id: 'txt' },\n            ],\n        listData: [\n        {\n            text: 'ProductName',\n            category: 'Drag or click the field to insert.',\n            htmlAttributes: { draggable: true }\n        },\n        {\n            text: 'ShipName',\n            category: 'Drag or click the field to insert.',\n            htmlAttributes: { draggable: true }\n        },\n        {\n            text: 'CustomerID',\n            category: 'Drag or click the field to insert.',\n            htmlAttributes: { draggable: true }\n        },\n        {\n            text: 'Quantity',\n            category: 'Drag or click the field to insert.',\n            htmlAttributes: { draggable: true }\n        },\n        {\n            text: 'UnitPrice',\n            category: 'Drag or click the field to insert.',\n            htmlAttributes: { draggable: true }\n        },\n        {\n            text: 'Discount',\n            category: 'Drag or click the field to insert.',\n            htmlAttributes: { draggable: true }\n        },\n        {\n            text: 'ShipAddress',\n            category: 'Drag or click the field to insert.',\n            htmlAttributes: { draggable: true }\n        },\n        {\n            text: 'ShipCity',\n            category: 'Drag or click the field to insert.',\n            htmlAttributes: { draggable: true }\n        },\n        {\n            text: 'ShipCountry',\n            category: 'Drag or click the field to insert.',\n            htmlAttributes: { draggable: true }\n        },\n        {\n            text: 'OrderId',\n            category: 'Drag or click the field to insert.',\n            htmlAttributes: { draggable: true }\n        },\n        {\n            text: 'OrderDate',\n            category: 'Drag or click the field to insert.',\n            htmlAttributes: { draggable: true }\n        }\n    ],\n    fields: {tooltip: 'category'},\n     toolbarItems : [\n            'New', 'Open', 'Separator', 'Undo',\n            'Redo',\n            'Separator',\n            {\n                prefixIcon: 'sf-icon-InsertMergeField',\n                tooltipText: 'Insert Field',\n                text: this.onWrapText('Insert Field'),\n                id: 'InsertField'\n            },\n            {\n                prefixIcon: 'sf-icon-FinishMerge',\n                tooltipText: 'Merge Document',\n                text: this.onWrapText('Merge Document'),\n                id: 'MergeDocument'\n            },\n            'Separator',\n            'Image',\n            'Table',\n            'Hyperlink',\n            'Bookmark',\n            'TableOfContents',\n            'Separator',\n            'Header',\n            'Footer',\n            'PageSetup',\n            'PageNumber',\n            'Break',\n            'Separator',\n            'Find',\n            'Separator',\n            'Comments',\n            'TrackChanges',\n            'Separator',\n            'LocalClipboard',\n            'RestrictEditing',\n            'Separator',\n            'FormFields',\n            'UpdateFields',\n        ],\n        header: 'Merge Field',\n        content:\n            '<div class=\"dialogContent\">'\n            // tslint:disable-next-line:max-line-length\n            + '<label class=\"e-insert-field-label\">Name:</label></br><input type=\"text\" id=\"field_text\" class=\"e-input\" placeholder=\"Type a field to insert eg. FirstName\">'\n            + '</div>',\n        showCloseIcon: true,\n        isModal: true,\n        width: '200px',\n        height: '200px',\n        close: this.closeFieldDialog,\n        buttons: [\n            {\n                'click':this.buttonclick,\n                buttonModel: {\n                    content: 'Ok',\n                    cssClass: 'e-flat',\n                    isPrimary: true,\n                },\n            },\n            {\n                'click': this.closeFieldDialog,\n                buttonModel: {\n                    content: 'Cancel',\n                    cssClass: 'e-flat',\n                },\n            },\n        ],\n   \n         \n        };\n    },  \n    provide:{\n        DocumentEditorContainer:[Toolbar]\n    },\n      methods: {\n        onExport: function (args) {\n            switch (args.item.id) {\n                case 'word':\n                    this.save('Docx');\n                    break;\n                case 'sfdt':\n                    this.save('Sfdt');\n                    break;\n                case 'txt':\n                    this.save('Txt');\n                    break;\n                case 'dotx':\n                    this.save('Dotx');\n                    break;\n            }\n        },\n        openExportDropDown: function () {\n            // tslint:disable-next-line:max-line-length\n            document.getElementById('word').setAttribute('title', 'Download a copy of this document to your computer as a DOCX file.');\n            // tslint:disable-next-line:max-line-length\n            document.getElementById('sfdt').setAttribute('title', 'Download a copy of this document to your computer as an SFDT file.');\n            // tslint:disable-next-line:max-line-length\n            document.getElementById('txt').setAttribute('title', 'Download a copy of this document to your computer as a TXT file.');\n            // tslint:disable-next-line:max-line-length\n            document.getElementById('dotx').setAttribute('title', 'Download a copy of this document to your computer as a DOTX file.');\n        },\n        save: function (format) {\n            // tslint:disable-next-line:max-line-length\n             this.$refs.doceditcontainer.ej2Instances.documentEditor.save( this.$refs.doceditcontainer.ej2Instances.documentEditor.documentName === '' ? 'sample' :  this.$refs.doceditcontainer.ej2Instances.documentEditor.documentName, format);\n        },\n        openBtnClick: function () {\n            this.$refs.uploadDocument.click();\n        },\n        printBtnClick: function () {\n            this.$refs.doceditcontainer.ej2Instances.documentEditor.print();\n        },\n        titleBarKeydownEvent: function (e) {\n            if (e.keyCode === 13) {\n                e.preventDefault();\n                document.getElementById(\"documenteditor_title_contentEditor\").contentEditable = 'false';\n                if (document.getElementById(\"documenteditor_title_contentEditor\").textContent === '') {\n                    document.getElementById(\"documenteditor_title_contentEditor\").textContent = 'Document1';\n                }\n            }\n        },\n        titleBarBlurEvent: function (args) {\n            if (document.getElementById(\"documenteditor_title_contentEditor\").textContent === '') {\n                document.getElementById(\"documenteditor_title_contentEditor\").textContent = 'Document1';\n            }\n            document.getElementById(\"documenteditor_title_contentEditor\").contentEditable = 'false';\n            this.$refs.doceditcontainer.ej2Instances.documentEditor.documentName = document.getElementById(\"documenteditor_title_name\").textContent;\n        },\n        titleBarClickEvent: function () {\n            this.updateDocumentEditorTitle();\n        },\n        updateDocumentEditorTitle: function () {\n            document.getElementById(\"documenteditor_title_contentEditor\").contentEditable = 'true';\n            document.getElementById(\"documenteditor_title_contentEditor\").focus();\n            window.getSelection().selectAllChildren(document.getElementById(\"documenteditor_title_contentEditor\"));\n        },\n        documentChangedEvent: function () {\n            var obj = this.$refs.doceditcontainer.ej2Instances.documentEditor;\n            this.documentTitle = obj.documentName === '' ? 'Untitled Document' : obj.documentName;\n            document.getElementById(\"documenteditor_title_name\").textContent = obj.documentName ;\n            setTimeout(() => { obj.scrollToPage(1); }, 10);\n        },\n        onselect: function (args) {\n        var fieldName = args.text;\n      //  listView.selectItem(undefined);\n        this.insertField(fieldName);\n    },\n    insertField: function(fieldName) {\n        var fileName = fieldName.replace(/\\n/g, '').replace(/\\r/g, '').replace(/\\r\\n/g, '');\n        var fieldCode = 'MERGEFIELD  ' + fileName + '  \\\\* MERGEFORMAT ';\n       // container.documentEditor.editor.insertField(fieldCode, '«' + fieldName + '»');\n        //container.documentEditor.focusIn();\n        this.$refs.doceditcontainer.ej2Instances.documentEditor.editor.insertField(fieldCode, '«' + fieldName + '»');\n        this.$refs.doceditcontainer.ej2Instances.documentEditor.focusIn();\n    },\n     onWrapText: function (text) {\n        var content = '';\n        var index = text.lastIndexOf(' ');\n        content = text.slice(0, index);\n        text.slice(index);\n        content += '<div class=\"e-de-text-wrap\">' + text.slice(index) + '</div>';\n        return content;\n    },\n    buttonclick: function()\n    {\n         var fieldNameTextBox = document.getElementById('field_text');\n                    var fieldName = fieldNameTextBox.value;\n                    if (fieldName !== '') {\n                        this.$refs.doceditcontainer.ej2Instances.documentEditor.editor.insertField('MERGEFIELD ' + fieldName + ' \\\\* MERGEFORMAT');\n                    }\n                    this.$refs.accessDialog.hide();\n                    this.$refs.doceditcontainer.ej2Instances.documentEditor.focusIn();\n    },\n   clickHandler: function (args) {\n            switch (args.item.id) {\n            case 'MergeDocument':\n                this.mergeDocument();\n                break;\n            case 'InsertField':\n                this.showInsertFielddialog();\n                break;\n        }\n        },\n     mergeDocument: function () {\n        this.$refs.doceditcontainer.ej2Instances.documentEditor.saveAsBlob('Docx').then((blob) => {\n            var exportedDocumment = blob;\n            var fileReader = new FileReader();\n            fileReader.onload = () => {\n                var base64String = fileReader.result;\n                var responseData= {\n                    fileName: this.$refs.doceditcontainer.ej2Instances.documentEditor.documentName + '.docx',\n                    documentData: base64String\n                };\n               // waitingPopUp = document.getElementById('waiting-popup');\n                //inActiveDiv = document.getElementById('popup-overlay');\n                this.showHideWaitingIndicator(true);\n                var baseUrl = 'https://document.syncfusion.com/web-services/docx-editor/api/documenteditor/MailMerge';\n                var httpRequest = new XMLHttpRequest();\n                httpRequest.open('POST', baseUrl, true);\n                httpRequest.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');\n                httpRequest.onreadystatechange = () => {\n                    if (httpRequest.readyState === 4) {\n                        if (httpRequest.status === 200 || httpRequest.status === 304) {\n                            this.$refs.doceditcontainer.ej2Instances.documentEditor.open(httpRequest.responseText);\n                        } else {\n                            // Failed to merge document\n                            DialogUtility.alert({\n                                title: 'Information',\n                                content: 'failure to merge document',\n                                showCloseIcon: true,\n                                closeOnEscape: true,\n                            });\n                        }\n                        this.showHideWaitingIndicator(false);\n                    }\n                };\n                httpRequest.send(JSON.stringify((responseData)));\n            };\n            fileReader.readAsDataURL(blob);\n        });\n    },\n     showHideWaitingIndicator: function (show) {\n         var waitingPopUp = document.getElementById('waiting-popup');\n        var inActiveDiv = document.getElementById('popup-overlay');\n        inActiveDiv.style.display = show ? 'block' : 'none';\n        waitingPopUp.style.display = show ? 'block' : 'none';\n    },\n     showInsertFielddialog: function () {\n      /*  var instance = this;\n        if (document.getElementById('insert_merge_field') === null || document.getElementById('insert_merge_field') === undefined) {\n            let fieldcontainer = document.createElement('div');\n            fieldcontainer.id = 'insert_merge_field';\n            document.body.appendChild(fieldcontainer);\n            \n                this.$refs.accessDialog.appendTo('#insert_merge_field');\n            fieldcontainer.parentElement.style.position = 'fixed';\n            fieldcontainer.style.width = 'auto';\n            fieldcontainer.style.height = 'auto';\n        }\n        this.$refs.accessDialog.close = () => { this.$refs.doceditcontainer.ej2Instances.documentEditor.focusIn();};\n        this.$refs.accessDialog.beforeOpen = () => { this.$refs.doceditcontainer.ej2Instances.documentEditor.focusIn();};\n        this.$refs.accessDialog.show();*/\n        this.$refs.accessDialog.show();\n        let fieldNameTextBox = document.getElementById('field_text');\n        fieldNameTextBox.value = '';\n        \n    },\n     closeFieldDialog: function () {\n        this.$refs.accessDialog.hide();\n        this.$refs.doceditcontainer.ej2Instances.documentEditor.focusIn();\n    },\n   \n     \n    },\n    mounted() {\n        this.$nextTick(function () {\n            \n          var obj = this.$refs.doceditcontainer.ej2Instances.documentEditor;\n          obj.open(JSON.stringify(<document-base64format>));\n          obj.documentName='Mail Merge';\n          this.$refs.doceditcontainer.ej2Instances.documentEditorSettings.showRuler = true;\n          this.$refs.doceditcontainer.ej2Instances.documentChange = () => {\n               this.$refs.accessDialog.hide();\n            };\n             this.$refs.accessDialog.hide();\n             this.$refs.doceditcontainer.ej2Instances.documentEditor.focusIn();\n           \n                    \n       });\n       \n        var items = this.toolbarItems;\n          this.$refs.doceditcontainer.ej2Instances.toolbarItems = items;\n        document.getElementById('de-flat-list').addEventListener('dragstart', (event) => {\n            event.dataTransfer.setData('Text', event.target.innerText);\n            event.target.classList.add('de-drag-target');\n        });\n        // Prevent default drag over for document editor element\n        document.getElementById('container').addEventListener('dragover', (event) => {\n            event.preventDefault();\n        });\n\n        // Drop Event for document editor element\n        document.getElementById('container').addEventListener('drop', (e) => {\n            var text = e.dataTransfer.getData('Text');\n            this.$refs.doceditcontainer.ej2Instances.documentEditor.selection.select({ x: e.offsetX, y: e.offsetY, extend: false });\n            this.insertField(text);\n        });\n\n        document.addEventListener('dragend', (event) => {\n            if (event.target.classList.contains('de-drag-target')) {\n                event.target.classList.remove('de-drag-target');\n            }\n        });\n         \n    }\n     \n    \n};\n\n</script>\n"
    },
    {
      "target": "src/components/docx-editor-mail-merge/DocxEditorView.vue",
      "content": "<template>\n  <DOCXEditor />\n</template>\n\n<script setup>\nimport DOCXEditor from '../../components/DOCXEditor.vue'\n</script>"
    }
  ]
}