6

I have a mean-stack website. I want to use ExecuteFunction to bind a button to launch this website in a Dialog box:

function doSomethingAndShowDialog(event) {
    clickEvent = event;
    Office.context.ui.displayDialogAsync("https://localhost:3000/try", {}, function () {})
}

Clicking on the button opens a dialog box with the following url, it does show the content of the page:

https://localhost:3000/try?_host_Info=excel|web|16.00|en-us|7fe9b4e9-d51e-bea5-d194-c817bc5ed4bc|isDialog#%2Ftry%3F_host_Info=excel%7Cweb%7C16.00%7Cen-us%7C7fe9b4e9-d51e-bea5-d194-c817bc5ed4bc%7CisDialog

However, in the console, there are Error: $rootScope:infdig Infinite $digest Loop at angular.bootstrap(document, ['myapp']):

var wait = setTimeout(myFunction, 1000);
Office.initialize = function (reason) {
    $(document).ready(function () {
        angular.bootstrap(document, ['myapp']) 
        console.log("bootstrapped inside Office.initialize");
        clearTimeout(wait);
    })
}

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

app = angular.module("myapp", []);
app.config(...);
app.controller(...);

If we just open https://localhost:3000/try in a browser, there is no error.

Does anyone know why that long url did not work with angular.bootstrap? How could we fix this?

Edit 1: a screenshot of the console for https://localhost:3000/try?_host_Info=excel.... Note that neither bootstrapped inside Office.initialize nor bootstrapped outside Office.initialize is displayed. But If I run https://localhost:3000/try in a browser, I will only see bootstrapped outside Office.initialize, when I call it from an Excel client, I will only see bootstrapped inside Office.initialize.

enter image description here

SoftTimur
  • 5,630
  • 38
  • 140
  • 292
  • 1
    You should call angular.bootstrap() after you've loaded or defined your modules.Check https://docs.angularjs.org/guide/bootstrap or more details. – Vivz Aug 04 '17 at 04:53
  • Where is `'myapp'` declared? – 31piy Aug 04 '17 at 05:42
  • 1
    You are calling `angular.bootstrap(document, ['myapp']) ` twice check it. You need to bootstrap it one time. – Burak Akyıldız Aug 04 '17 at 06:11
  • Guys, because of `setTimeout`, I can bootstrap either inside or outside `Office.initialize`, so `angular.bootstrap(document, ['myapp'])` will always be executed one time. In the code, the declaration of `myapp` is written after the bootstrap block, but my tests show that the written order is not that important... – SoftTimur Aug 04 '17 at 09:22
  • 1
    Actually, I think you are calling it twice. Both Office.init and myFunction wire up to the Document.Ready event. As soon as that event fires, both of those callbacks will be triggered. – Marc LaFleur Aug 04 '17 at 21:02
  • @MarcLaFleur-MSFT please see my update, neither `bootstrapped inside Office.initialize` nor `bootstrapped outside Office.initialize` is displayed for `https://localhost:3000/try?_host_info...`. `setTimeout` could make sure `bootstrap` is called once for `https://localhost:3000/try`, how come it did not work with `https://localhost:3000/try?_host_info...` – SoftTimur Aug 04 '17 at 22:52
  • @SoftTimur , you are calling it twice because `inside Office initialize ` will be called as it a javascript function expression and your `SetTimeOut` method will also be calling again after wait time. Now answering your question why not with `https://localhost:3000/try` because it is no where releated to the Office.initalize method so that is the reason bootstrap will be done only once in that particular case – Krsna Kishore Aug 05 '17 at 08:49
  • @Webruster It is `Office.context.ui.displayDialogAsync` which added systematically `?_host_Info=excel|...` to the url... Do you know how to disable this? – SoftTimur Aug 05 '17 at 12:09
  • @SoftTimur systematically means , on where it would be adding and just want to be sure that are you using Jquery any where? – Krsna Kishore Aug 05 '17 at 12:11
  • @SoftTimur after a bit of investigation i went a bit deeper i went to that [execution function](https://github.com/OfficeDev/Office-Add-in-Dialog-API-Simple-Example) and there that repo is using the Jquery internally so the reason for your infinite digest loop is that `$` the same is used by the `angular` and also `Jquery` so `angular` things it as its own function . one way to mitigate this issue is that you can fork that repo and try to change the `$` to `jQuery` and test to load it . its worth to give a try – Krsna Kishore Aug 05 '17 at 12:16
  • @Webruster I tried to use `jQuery(document)` instead of `$(document)`, it still had the same error... – SoftTimur Aug 05 '17 at 12:25
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/151140/discussion-between-webruster-and-softtimur). – Krsna Kishore Aug 05 '17 at 12:25

1 Answers1

1

It sounds like you're trying to wire up a page that can operate as either an add-in or a stand-alone page. Whenever possible it is best to maintain separate views for each use case. If nothing else, it makes everything a lot more straight forward. Combining them is likely creating far more overhead and headache that it's worth.

Part of your issue here is that you've got two separate code paths and you're assuming only one path will execute at a time. When loaded in a browser this is true, it will simply ignore the Office.initialize function. When loaded within Office however it will execute both paths. One will be executed by Office, the other will be executed by setTimeOut after 1 second.

If you have two distinct code paths where only one is ever executed, you need to test to determine if you're operating as an add-in or as a standalone page. This is where those query parameters come into play. If you have a _host_Info query parameter defined then you're operating within Office. For example:

if (getParameterByName('_hostInfo')) { // _hostInfo is defined
    Office.initialize = function (reason) {
        $(document).ready(function () {
            angular.bootstrap(document, ['myapp'])
            console.log("bootstrapped inside Office.initialize");
        });
    }
} 
else { // _hostInfo is not defined
    $(document).ready(function () {
        angular.bootstrap(document, ['myapp'])
        console.log("bootstrapped outside Office.initialize");
    })
}

Note that getParameterByName() here is a function pulled from this answer. You could use any method you prefer however.

Marc LaFleur
  • 31,987
  • 4
  • 37
  • 63
  • Thank you for your answer... I do want to use a function to check if the page is operating as an add-in or as a standalone page. But it seems that I can only use `ui-router` to distinguish `https://localhost:3000/try` and `https://localhost:3000/try?_host_Info...`, and I don't think we can put `angular.bootstrap` inside `$stateProvider.state(...)`, can we? – SoftTimur Aug 09 '17 at 23:24