0
votes

We are encountering problems when trying to load our outlook appointment addin. Our command shows up in the ribbon ui and the addin is trying to start and we can trace the calls to our wev-app. We are not getting any errors, 404 or 500 in the tracing and the service responds with our first html-page containing a text and a button to initiate our authentication.

But after the html is returned outlook just stops the spinner for the addin and nothing is showed. Is there any good ways to debug this to understand what is happening?

The html-page is very simple and only contains the code below.

<head>
    <title>Office-bokning</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="format-detection" content="telephone=no">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://appsforoffice.microsoft.com/fabric/2.2.0/fabric.min.css">
    <link rel="stylesheet" href="https://appsforoffice.microsoft.com/fabric/2.2.0/fabric.components.min.css">
    <script src="https://appsforoffice.microsoft.com/lib/1/hosted/Office.js" type="text/javascript"></script>
    <!--[authentication-popup-script]-->
    <script>
        startCheck = function () {
            var checkCode = setInterval(function () {

                localStorage.setItem('dummy', "dummy");
                localStorage.removeItem('dummy');
                var code = localStorage.getItem('code');
                var externalProviderUserId = localStorage.getItem('externalProviderUserId');

                function readCookie(name) {
                    var nameEQ = name + "=";
                    var ca = document.cookie.split(';');
                    for (var i = 0; i < ca.length; i++) {
                        var c = ca[i];
                        while (c.charAt(0) == ' ') c = c.substring(1, c.length);
                        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
                    }
                    return null;
                }

                var fallbackCode;
                var fallbackExternalProviderUserId;

                if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {
                    fallbackCode = readCookie('NAME_OF_COOKIE');
                    fallbackExternalProviderUserId = readCookie('externalProviderUserId');
                }
                console.log("code " + code);
                if (code || fallbackCode) {
                    clearInterval(checkCode);

                    var http = new XMLHttpRequest();
                    var url = [URL]
                    http.open("POST", url, true);

                    //Send the proper header information along with the request
                    http.setRequestHeader("Content-type", "text/plain");
                    //var that = this;
                    http.onreadystatechange = function () {
                        if (http.readyState == 4 && http.status == 200) {
                            localStorage.removeItem('code');
                            localStorage.removeItem('externalProviderUserId');
                            window.location.href = "[URL]";
                            //location.reload();
                        }
                    }
                    http.send(params);
                }
            }, 1000);
        }

        startCheck();
    </script>
</head>
    <body class="container-fluid" style="padding-left: 0px; padding-right: 0px; height: 100%">
        <p>
            Some text describing the addin...
        </p>
        <!--[popup-button]-->
        <script>
            Office.initialize = function (reason) {
                console.log("authorize office init" + reason);
                var butan = document.getElementById('loginButton');
                if (butan)
                    butan.style.display = 'block';
            }

            function commandFunction(event) {
                event.completed();
            }
        </script>
    </body>
2

2 Answers

3
votes

TL;DR : It seems you want to pop up a page for auth. Use the displayDialogAsync API to do that.

Looking at your code, I don't see anything wrong with it. Moreover, the behavior you described is actually correct according to the code you have.

I see that you have a function named "commandFunction" that takes in an "event" parameter. My guess is that you have an ExecuteFunction in your manifest that calls commandFunction.

So when a user clicks on your add-in's button in the ribbon ui of an appointment window, Outlook will load your html webpage, invoke "Office.initialize", show a default spinner for your app just above the "Subject" field of the appointment window, and then call "commandFunction". The only code inside this function is "event.completed", so Outlook calls that code, which basically ends the execution of your app, at which point Outlook removes the default spinner to signal completion. That's exactly what you are experiencing.

You have to run any relevant code inside "commandFunction" before calling "event.completed". So for example, you can add code that will add a notification message/infobar to the appointment before calling "event.completed". Sample code below:

function commandFunction(event)
{
    Office.context.mailbox.item.notificationMessages.addAsync
    (
        "some_unique_id_such_as_a_guid",
        {
            type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage,
            persistent: false,
            message: "hello world",
            icon: "default_icon"
        },
        function (asyncResult)
        {
            // check asyncResult.status
            // do something
            event.completed(true);
        }
    );
}

It appears that you want to open an html window for the user to authenticate before proceeding with the execution of your app. In that case, you should use the "displayDialogAsync" API by calling it inside "commandFunction" before "event.completed". This will open an IE window that points to authentication page URL. Sample code below:

function commandFunction(event)
{
    Office.context.ui.displayDialogAsync
    (
        "https://ur/to/auth/page",
        {
            width: 50,
            height: 45,
            requireHTTPS: true
        },
        function (asyncResult)
        {
            // check asyncResult.status
            // do something
            event.completed(true);
        }
    );
}

The documentation for the displayDialogAsync API is at: https://github.com/OfficeDev/office-js-docs/blob/master/reference/shared/officeui.md

For debugging, open IE, go to 'Internet Options' -> 'General tab' -> click on 'Settings' button to open the 'Website Data Settings' window. In the 'Temporary Internet Files' tab, under 'Check for newer versions of stored pages', select 'Every time I visit the webpage'. Click Ok.

Now go to 'Advanced' tab -> 'Settings' section and uncheck the following:

  • Disable script debugging (Internet Explorer)
  • Disable script debugging (Other)

Then check the following:

  • Display a notification about every script error

Then add "debugger;" as the first line in "commandFunction":

function commandFunction(event)
{
    debugger;
    // add other code below...
}

This will prompt you to debug your code when you run the app. And you can debug in Visual Studio and go through your code if you have any other issues.

-1
votes

The HTML you pasted doesn't have a reference to Office.js: <script src="https://appsforoffice.microsoft.com/lib/1/hosted/Office.js" type="text/javascript"></script>