Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Excel Javascript Add-in: how to open ExecuteFunction in the taskpane rather than new iframe?

I'm trying to use the Excel Javascript API to create an addin that:

  • Adds multiple buttons on the Home tab.
  • Each of the buttons opens the taskpane to a different screen.
  • Each of these taskpanes runs in the same runtime (e.g. I can share data between them with just setting data in window.data = "data").

As far as I understand, it is not possible to do this with multiple ShowTaskpane actions on the buttons, as this does not appear work with the shared runtime.

The approach I'm taking currently is:

  1. Set my function file as
<FunctionFile resid="Taskpane.Url"/>

(where <bt:Url id="Taskpane.Url" DefaultValue="https://localhost:3000/taskpane.html"/>)

  1. Define the following actions:
<Control xsi:type="Button" id="FirstButton">
    ...
    <Action xsi:type="ExecuteFunction">
        <FunctionName>first</FunctionName>
    </Action>
</Control>
<Control xsi:type="Button" id="SecondButton">
    ...
    <Action xsi:type="ExecuteFunction">
        <FunctionName>second</FunctionName>
    </Action>
</Control>
  1. Define first and second as a functions in the global scope (and defined in the taskpane.html file). Each of these functions a) sets some state inside the Taskpane app (to get it to show something different, depending on the function call), then calls Office.addin.showAsTaskpane(). The code looks generally like:

the code for the first function called from the button

However, this does not work as expected. Namely, it opens the taskpane in a separate iframe to the side of the taskpane. It looks like this:

share function opens in a new iframe

When I add a Office.addin.showAsTaskpane() call to the share function, it looks like this:

showAsTaskpane just causes the taskpane to open as well as the new iframe

How can I use the Execute functions actions but do so within the taskpane? I want one shared runtime, and I want all of it to open and be within the taskpane itself. The documentation makes it seem like AppDomains can make this happen, but I'm not sure what I'm doing wrong.

Thanks for any information -- I really appreciate it!

like image 670
Nate Rush Avatar asked Jun 12 '20 18:06

Nate Rush


1 Answers

The key problem here I think is you want to change some state in your taskpane based on the function executions. That's actually easy and you don't need the shared runtime for that.

In your taskpane, at the initialization part, you have to register the event listener for storage.

window.addEventListener('storage', () => {
  console.log('your local storage has changed');
});

In your functions, you could utilize the local storage, writing values in there which in your taskpane you'll have access to when the event is raised.

// example globally exposed function to be called using ExecuteFunction
function first(event) {
   localStorage.setItem('routePath', 'firstRoute');
   event.completed();
}

then in your taskpane-app you could have

window.addEventListener('storage', () => {
  const askedPath = localStorage.getItem('routePath');
  if (askedPath !== existingPath) {
    reRouteApp(localStorage.getItem('routePath')
  }
});

Depending on your framework of choice, you may want to watch out for how you register this event listener. To provide an example, if you're using react and hash-router, you could have your re-route method like so:

const reRouteApp = (route) => {
  window.location.hash = route;
}

while making sure you register the listener event on onComponentMount of the app.js or with useEffect to ensure you don't end up with multiple listeners.

like image 131
Mavi Domates Avatar answered Oct 10 '22 12:10

Mavi Domates