ContentControl operations slow down Word Online

Viewed 82

Expected Behavior

Word Online is usable and does not crash or slow down drastically when editing ContentControls.

Current Behavior

When inserting HTML into a ContentControl via contentControl.insertHtml("mytext", "Replace") the operation takes more time every call. I tried using the clear()-function and inserting without replacing but that caused the same issue. After trying that I thought I narrowed down that clearing the ContentControl was the issue but after further investigation, every operation (replace, clear, insert) editing the ContentControl gets worse. It can take minutes to do one operation. After a few tests the document breaks completely after clicking in the ContentControl and hitting any key own my keyboard. I tried clearing my cache and opening the document in a private Browser tab, but nothing worked.

I will attach my document.

Test Doc.docx

Steps to Reproduce

I created a new Word Web Add-In in VisualStudio and created a minimal example to reproduce the issue.

Home.js:

    "use strict";

    var messageBanner;

    // Die Initialisierungsfunktion muss bei jedem Laden einer neuen Seite ausgeführt werden.
    Office.initialize = function (reason) {
        $(document).ready(function () {
            $('#insert-button').click(insert);
            $('#clear-button').click(clear);
            $('#replace-button').click(replace);
            loadCc();
        });
    };

    var cc;

    function loadCc() {
        Word.run(ctx => {
            let ccs = ctx.document.body.contentControls;

            ctx.load(ccs);
            
            return ctx.sync().then(function () {
                console.log(ccs.items.length);
                cc = ccs.items[0];
            });
        });
    }


    let string = "a";

    function clear() {
        if (cc) {
            let start = new Date().getTime();
            cc.clear();
            cc.context.sync().then(() => {
                let clear = new Date().getTime();
                console.log("Clear took: " + (clear - start));
            });
        }
    }

    function insert() {
        if (cc) {
            //cc.insertHtml(string, "Replace");
            let start = new Date().getTime();

            cc.insertHtml(string, "Start");
            cc.context.sync().then(() => {
                let insert = new Date().getTime();
                console.log("Insert took: " + (insert - start));
            });
        }
    }

    function replace() {
        if (cc) {
            let start = new Date().getTime();
   
            cc.insertHtml(string, "Replace");
            cc.untrack();
            cc.context.sync().then(() => {
                let insert = new Date().getTime();
                console.log("Replace took: " + (insert - start));
            });
        }
    }

    //$$(Helper function for treating errors, $loc_script_taskpane_home_js_comment34$)$$
    function errorHandler(error) {
        // $$(Always be sure to catch any accumulated errors that bubble up from the Word.run execution., $loc_script_taskpane_home_js_comment35$)$$
        showNotification("Fehler:", error);
        console.log("Error: " + error);
        if (error instanceof OfficeExtension.Error) {
            console.log("Debug info: " + JSON.stringify(error.debugInfo));
        }
    }

    // Eine Hilfsfunktion zum Anzeigen von Benachrichtigungen.
    function showNotification(header, content) {
        $("#notification-header").text(header);
        $("#notification-body").text(content);
        messageBanner.showBanner();
        messageBanner.toggleExpansion();
    }
})();

Home.html

<html>
<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    <title>Word Add-In with Commands Sample</title>

    <script src="Scripts/jquery-3.5.0.js" type="text/javascript"></script>
    <script src="Scripts/MessageBanner.js" type="text/javascript"></script>
    <script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js" type="text/javascript"></script>



    <script src="Home.js" type="text/javascript"></script>
    <link href="Home.css" rel="stylesheet" type="text/css" />
    <link href="../Content/Button.css" rel="stylesheet" type="text/css" />
    <link href="../Content/MessageBanner.css" rel="stylesheet" type="text/css" />



    <link rel="stylesheet" href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/9.6.0/css/fabric.min.css">


<body class="ms-Fabric" dir="ltr">
    <div id="content-main">
        <div class="padding">
            <button class="Button Button--primary" id="insert-button">
                Insert
            </button>
            <button class="Button Button--primary" id="clear-button">
                Clear
            </button>
            <button class="Button Button--primary" id="replace-button">
                Replace
            </button>
        </div>
    </div>

    <div class="MessageBanner" id="notification-popup">
        <div class="MessageBanner-content">
            <div class="MessageBanner-text">
                <div class="MessageBanner-clipper">
                    <div class="ms-font-m-plus ms-fontWeight-semibold" id="notification-header"></div>
                    <div class="ms-font-m ms-fontWeight-semilight" id="notification-body"></div>
                </div>
            </div>
            <button class="MessageBanner-expand" style="display:none"><i class="ms-Icon ms-Icon--chevronsDown"></i> </button>
            <div class="MessageBanner-action"></div>
        </div>
        <button class="MessageBanner-close"> <i class="ms-Icon ms-Icon--ChromeClose"></i> </button>
    </div>
</body>
</html>
1 Answers

To fix the issue it is necessary to use async methods and await the context.sync()-Calls instead of using the Promises then() callbacks.

Fixed Code:


(function () {
    "use strict";

    var messageBanner;

    // Die Initialisierungsfunktion muss bei jedem Laden einer neuen Seite ausgeführt werden.
    Office.initialize = function (reason) {
        $(document).ready(function () {
            $('#insert-button').click(insert);
            $('#clear-button').click(clear);
            $('#replace-button').click(replace);
            loadCc();
        });
    };

    var cc;

    async function loadCc() {
        await Word.run(async ctx => {
            let ccs = ctx.document.body.contentControls;

            ctx.load(ccs);
            
            await ctx.sync();

            console.log(ccs.items.length);
            cc = ccs.items[0];
        });
    }


    let string = "a";

    async function clear() {
        if (cc) {
            let start = new Date().getTime();
            cc.clear();
            await cc.context.sync();
            let clear = new Date().getTime();
            console.log("Clear took: " + (clear - start));
        }
    }

    async function insert() {
        if (cc) {
            //cc.insertHtml(string, "Replace");
            let start = new Date().getTime();

            cc.insertHtml(string, "Start");
            await cc.context.sync();

            let insert = new Date().getTime();
            console.log("Insert took: " + (insert - start));
        }
    }

    async function replace() {
        if (cc) {
            let start = new Date().getTime();
   
            cc.insertHtml(string, "Replace");
            await cc.context.sync();

            let insert = new Date().getTime();
            console.log("Replace took: " + (insert - start));
        }
    }

    //$$(Helper function for treating errors, $loc_script_taskpane_home_js_comment34$)$$
    function errorHandler(error) {
        // $$(Always be sure to catch any accumulated errors that bubble up from the Word.run execution., $loc_script_taskpane_home_js_comment35$)$$
        showNotification("Fehler:", error);
        console.log("Error: " + error);
        if (error instanceof OfficeExtension.Error) {
            console.log("Debug info: " + JSON.stringify(error.debugInfo));
        }
    }

    // Eine Hilfsfunktion zum Anzeigen von Benachrichtigungen.
    function showNotification(header, content) {
        $("#notification-header").text(header);
        $("#notification-body").text(content);
        messageBanner.showBanner();
        messageBanner.toggleExpansion();
    }
})();

Related