Check if Office.js is loaded outside of Office client
Asked Answered
G

4

9

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.

Gong answered 8/7, 2017 at 17:51 Comment(4)
I just made an issue, but obviously they cannot make an API quickly, so a workaround will be appreciated...Gong
This capability (using Office.js outside an add-in) sounds very promising, but I can't picture how it works. How does it connect to an Office file? How does the app use Office.js? I can't find any documentation.Roberson
The goal is not to use Office.js outside an add-in. It is just because this app servers a web site and an Office add-in at the same time, it is simple to load Office.js for both of the two cases. But we do need to check in the code if it is loaded as a web site or an add-in.Gong
I've considered making my code work w/o Office.js, but I have a LOT of data/code that is either getting data from worksheet or pasting to worksheet. It could def be done, and then I'd export to Excel via Excel.JS. But really, main reason for wanting this was simply so I can debug outside Excel. I don't want to load Excel just to test changes that don't deal w/ Office or Excel objects, I can just test in pure HTML/JS w/ a Browser. Also, i needed to debug the HTML/JS using a CORs extension..Koa
C
1

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

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

Criticize answered 2/11, 2017 at 5:48 Comment(1)
This is deprecated/abandoned FYI.Koa
D
5

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.

enter image description here

Dhahran answered 8/7, 2017 at 19:25 Comment(4)
Thank you, Michael... Please see my edit 1. I am not sure your solution of Script Lab works for me, do you have a workaround?Gong
What if you did your initialization regardless, but still had "Office.initialized" as well, to set a flag that you are in fact in Office? I don't know what other workaround to suggest, but again, I do encourage you to open a suggestion bug -- coming from a customer directly, I think it will help in getting this prioritized (and that way, too, you'll be subscribed to see updates on that issue).Dhahran
I implemented the workaround you did for Script Lab, it worked for me. However, the downside is we need to wait several seconds more when we load it in a browser as a web site. Is it the same for Script Lab?Gong
@MichaelZlatkovsky-Microsoft its a real thing now! And you were close, its Office.onReady. I was able to parse the info to determine if running in Office.Koa
C
1

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

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

Criticize answered 2/11, 2017 at 5:48 Comment(1)
This is deprecated/abandoned FYI.Koa
K
0

Here is how I am doing this:

Inside commands.js I have the following:

Office.onReady(async function (info) {
  await Office_Loaded_Check(info)
});

and I have a separate file loaded globals.js with the following:

function getGlobal() {
  return typeof self !== "undefined"
    ? self
    : typeof window !== "undefined"
    ? window
    : typeof global !== "undefined"
    ? global
    : undefined;
}

var g = getGlobal();

//Office Loaded
async function Office_Loaded_Check(info) {
  if (info["host"] == null) {
    //All the below allow code to run without Error when using Edge to debug outside Office
    console.log('Setting Fake Office/Excel Objs Vars for Running Outside Office')

    //Office
    Office.addin = {};
    Office.addin.setStartupBehavior = function () {
      return true;
    };
    Office.addin.showAsTaskpane = function () {
      return true;
    };

    Office.StartupBehavior = {};
    Office.StartupBehavior.none = null;

    //Excel
    var Excel = {};
    Excel.run = async function (Excel_Run) {
      var context = {};
      context.sync = function () {
        return true;
      };
      Excel_Run(context);
      return true;
    };

    //Excel Obj for No Error in Edge/NodeJS Mode
    g.Excel = Excel;

 }
}

Bonus, I also sometimes run my code server side in Node and I use this:

Example: If NodeJS then -- const xmlserializer = require('xmlserializer'); //XMLSerializer only available client side, want code to be usable both client and server side, so use xmlserializer

var Is_NodeJS_Bool = false;
g.Is_NodeJS_Bool = Is_NodeJS_Bool;
if (typeof window === "undefined") {
  Is_NodeJS_Bool = true;
  console.log("Is_NodeJS_Bool = true");
} else {
  var module = {};
  //NodeJS Var for No Error in Edge/Office Mode
  g.module = module;
}

That way, I can have the following on my code w/o errors in Edge:

//Server_Side NodeJS
module.exports = {
    ...,
};
Koa answered 2/9, 2023 at 2:18 Comment(0)
K
0

This works for me:

const bLoadedInOffice = (window.external && typeof window.external.GetContext !== "undefined");

This is basically how OfficeJS detects itself running outside of Office.
window.external.GetContext is "function() { return context; }" (=not undefined) when running in Office.
(based on OSF.InitializationHelper.prototype.getAppContext @ "o15apptofilemappingtable.js")

Kinetic answered 3/8, 2024 at 19:18 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.