Where could we put `Office.onReady()` to make sure Office.js could fully load every time

3.1k views Asked by At

I'm debugging an Excel add-in built in React. Previously, the developer coded the app as if it was a website rather than an Excel add-in, and did not pay attention to Office.js. As a result, when we run it in Excel, we have the famous error Error: Office.js has not fully loaded. Your app must call "Office.onReady()" as part of it's loading sequence (or set the "Office.initialize" function). If your app has this functionality, try reloading this page.

enter image description here

I searched for Office.onReady and Office.initialize in the whole project, I did not find them.

Here is frontend/src/index.tsx, where dva is a "framework based on redux, redux-saga and react-router (Inspired by elm and choo)".

import 'react-app-polyfill/ie11';
import 'react-app-polyfill/stable';
import dva from 'dva';
import './index.css';
import router from './router';
import AuthModel from './models/auth';
import SubscribtionModel from './models/subscription';
import AppModel from './models/app';
import { initializeIcons } from 'office-ui-fabric-react/lib/Icons';

//@ts-ignore
//import createLoading from 'dva-loading';

// 1. Initialize
const app = dva();
//app.use(createLoading());

// 2. Plugins
// app.use({});

// 3. Model
//@ts-ignore
app.model(AuthModel);
app.model(SubscribtionModel)
app.model(AppModel);
// 4. Router
//@ts-ignore
app.router(router);

// 5. Start
app.start('#root');

initializeIcons();

Does anyone know where I should put Office.onReady() such that we could make sure Office.js can fully load every time the add-in is launched?

Edit 1:

I tried to mimic this file and changed one of my index.tsx to

  render() {
    const { items, farItems } = this.props;

    console.log("Here is Office:");
    console.log(Office);

    return (
      <AwaitPromiseThenRender
        promise={Promise.resolve().then(async () => {
              await Office.onReady();
        })}
      >
        <CommonHeader
          items={items.map((item: IHeaderItem) => this.renderItem(item))}
          farItems={farItems.map((item: IHeaderItem) => this.renderItem(item))}
        />
      </AwaitPromiseThenRender>
    );
  } 

It returned a TypeScript error: Property 'onReady' does not exist on type 'typeof Office'. TS2339, whereas the object Office is well printed in the console. Does anyone have any idea of the problem?

Edit 2:

I tried to add the following code in my frontend/src/index.tsx above. It still returned Property 'onReady' does not exist on type 'typeof Office'. TS2339.

export function render(oldRender: () => void) {
    Office.onReady((reason: any) => {
      oldRender();
    });
}
2

There are 2 answers

0
wellgone On

If you use class component,you can put it in componentWillMount.

If you use function component, you can put it in Effect hooks like this:

useEffect(()=>{
    Office.onReady(function(info) {
      console.log(info);
      if (info.host === Office.HostType.Word) {
        console.log("hhhhhhhhhhh")
      }
      if (info.platform === Office.PlatformType.PC) {
        // Make minor layout changes in the task pane.
        console.log("ooooooooooooo")
      }
      console.log(`Office.js is now ready in ${info.host} on ${info.platform}`);
    });
  })
0
Ketobomb On

You can put it in componentWillMount

async componentWillMount() {
 await hostApp.onReady();}