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.

SoftTimur
  • 5,630
  • 38
  • 140
  • 292
  • I just [made an issue](https://github.com/OfficeDev/office-js/issues/5), but obviously they cannot make an API quickly, so a workaround will be appreciated... – SoftTimur Jul 09 '17 at 01:34
  • 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. – Andrew Hall Jul 11 '17 at 03:22
  • 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. – SoftTimur Jul 11 '17 at 04:32
  • 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.. – FreeSoftwareServers Sep 02 '23 at 02:21

3 Answers3

6

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

  • 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? – SoftTimur Jul 08 '17 at 20:25
  • 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). – Michael Zlatkovsky - Microsoft Jul 08 '17 at 23:31
  • 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? – SoftTimur Jul 09 '17 at 22:21
  • @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. – FreeSoftwareServers Sep 02 '23 at 02:24
2

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

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

Tie Cheng
  • 60
  • 6
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 = {
    ...,
};
FreeSoftwareServers
  • 2,271
  • 1
  • 33
  • 57