Check if Office.js is loaded outside of Office cli

2019-02-14 16:12发布

问题:

If we load a webpage referencing office.js outside Office client, we will get a warning: Office.js is loaded outside of Office client.

This information is useful.

Does anyone know if there is an API to check that inside my code?

Edit 1:

I explain a little bit my scenario and why I ask this question. I am making an application with angularjs which can be loaded in a browser as a web page or in Office as an add-in. And I realise that we should not do <body ng-app="myApp"> and angular.bootstrap(document, ['myApp']) together, otherwise controllers will execute twice. So I decided to not write <body ng-app="myApp"> and always use angular.bootstrap in both cases (ie, web page & add-in).

So for a web page, I could write:

$(document).ready(function () {
    angular.bootstrap(document, ['myApp'])  
})

app = angular.module('myApp', ['ui.router', 'ui.bootstrap'])
...

So for a web page, I need to write angular.bootstrap inside Office.initialize, and share other code with the case of add-in:

Office.initialize = function (reason) {
    $(document).ready(function () {
        angular.bootstrap(document, ['myApp'])
    });
}

app = angular.module('myApp', ['ui.router', 'ui.bootstrap'])
// share the same code

However, if I write these two cases together as follows, it works for a web page, whereas I gives Error: ng:btstrpd App Already Bootstrapped with this Element for add-in.

$(document).ready(function () {
    angular.bootstrap(document, ['myApp'])
    console.log("bootstrapped outside Office.initialize")   
})

Office.initialize = function (reason) {
    $(document).ready(function () {
        angular.bootstrap(document, ['myApp'])
        console.log("bootstrapped inside Office.initialize")
    })
}

app = angular.module('myApp', ['ui.router', 'ui.bootstrap']).

If I set a flag, console will display bootstrapped outside Office.initialize followed by isBootstrapped, then running the code will show that Office.context or Office.context.document is undefined:

var isBootstrapped = false;

$(document).ready(function () {
    angular.bootstrap(document, ['myApp'])
    isBootstrapped = true
    console.log("bootstrapped outside Office.initialize")
})

Office.initialize = function (reason) {
    $(document).ready(function () {
        if (isBootstrapped) console.log("isBootstrapped")
        else {
            angular.bootstrap(document, ['myApp'])
            console.log("bootstrapped inside Office.initialize")
        }
    })
}

app = angular.module('myApp', ['ui.router', 'ui.bootstrap'])

So I really need an efficient way to check if Office.js is loaded outside of Office client (ie, whether it is a web page or an add-in), to decide which piece of angular.bootstrap should be executed.

回答1:

One way is to use https://github.com/OfficeDev/office-js-helpers.

Both OfficeHelpers.Utilities.host and OfficeHelpers.Utilities.platform provide useful information.



回答2:

There is no such API at the moment, though we've internally talked about having an Office.ready() (similar in spirit to $(document).ready(...)), that would fire whenever Office.js is done initializing (whether in the add-in or not).

You are welcome to suggest it on https://github.com/OfficeDev/office-js, and post a link here. My thought on the API is that it would take in a callback (just like $(document).ready(...) that it would fire when ready, and would also be available in promise form (so you can do await Office.ready()). Do you think that works for your scenario?

FWIW: As a workaround, for Script Lab, we wrap a Promise around Office.initialized (and make sure to do it early on in the loading of the application, else it won't fire if it's much later), wait for it, and if we don't receive anything in the first 3 seconds we show a set of buttons to let the user help disambiguate for us. See https://script-lab.azureedge.net/ for an example of what that looks like. Not perfect, but was OK-ish for our scenario. I do encourage you to file a suggestion bug on the office-js repo, though, adding your concrete scenario to back it.