The Url of dialog box does not work with angular.bootstrap (infinite $digest Loop)
Asked Answered
D

1

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

Dieselelectric answered 1/8, 2017 at 17:58 Comment(12)
You should call angular.bootstrap() after you've loaded or defined your modules.Check docs.angularjs.org/guide/bootstrap or more details.Chabazite
Where is 'myapp' declared?Noma
You are calling angular.bootstrap(document, ['myapp']) twice check it. You need to bootstrap it one time.Tophole
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...Dieselelectric
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.Colwin
@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...Dieselelectric
@Dieselelectric , 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 caseTenderize
@Webruster It is Office.context.ui.displayDialogAsync which added systematically ?_host_Info=excel|... to the url... Do you know how to disable this?Dieselelectric
@Dieselelectric systematically means , on where it would be adding and just want to be sure that are you using Jquery any where?Tenderize
@Dieselelectric after a bit of investigation i went a bit deeper i went to that execution function 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 tryTenderize
@Webruster I tried to use jQuery(document) instead of $(document), it still had the same error...Dieselelectric
Let us continue this discussion in chat.Tenderize
C
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.

Colwin answered 7/8, 2017 at 20:20 Comment(1)
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?Dieselelectric

© 2022 - 2024 — McMap. All rights reserved.