We develop Excel add-ins. From time to time, we observe this 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.
It did not seem very blocking. However, now we realize that when this happens in Mac for Excel, the taskpane becomes a blank page. Users have to reload the page again to not see this error and load well the page.
So we would like to find a robust way to avoid this error.
Our add-ins are built with Reactjs and dva, which is a framework based on redux, redux-saga and react-router. Here is frontend/src/index.tsx
:
import 'react-app-polyfill/ie11';
import 'react-app-polyfill/stable';
import dva from 'dva';
import router from './router';
import AuthModel from './models/auth';
import SubscribtionModel from './models/subscription';
import AppModel from './models/app';
import SpreadsheetModel from './models/spreadsheet';
import UsageModel from './models/usage';
import SettingsModel from './models/settings';
import { initializeIcons } from 'office-ui-fabric-react/lib/Icons';
initializeIcons();
const app = dva();
app.model(AuthModel);
app.model(SubscribtionModel)
app.model(AppModel);
app.model(SpreadsheetModel);
app.model(UsageModel);
app.model(SettingsModel);
app.router(router);
app.start('#root');
Here is src/router.tsx
:
import React from 'react';
import { routerRedux, Switch, Route } from 'dva/router';
import Layout from './layouts';
import LoginPage from './components/LoginPage';
import Welcome from './components/welcome';
import SocialLoginSuccess from './components/socialLoginSuccess';
import { AwaitPromiseThenRender } from './components/AwaitPromiseThenRender';
const { ConnectedRouter } = routerRedux;
function RouterConfig({ history }: any) {
//@ts-ignore
return (
<AwaitPromiseThenRender
//@ts-ignore
promise={typeof window.__$$notInOffice !== "undefined" ? Promise.resolve(true) : Office.onReady()}
>
<ConnectedRouter history={history}>
<Layout>
<Switch>
<Route path="/sign">
<LoginPage />
</Route>
<Route path="/home">
<Welcome />
</Route>
<Route path="/app">
<App />
</Route>
... ...
... ...
</Layout>
</ConnectedRouter>
</AwaitPromiseThenRender>
);
}
export default RouterConfig;
Here is src/components/AwaitPromiseThenRender/index.tsx
:
import React, { Component } from 'react';
interface IProps {
promise: Promise<any>;
children: React.ReactNode;
}
interface IState {
promiseHasResolved: boolean;
}
export class AwaitPromiseThenRender extends Component<IProps> {
state: IState = { promiseHasResolved: false };
constructor(props: IProps) {
super(props);
props.promise
.then(() => this.setState({ promiseHasResolved: true }))
.catch(e => console.log("invokeGlobalErrorHandler(e)"))
}
render() {
const { children } = this.props;
const { promiseHasResolved } = this.state;
return promiseHasResolved ? children : null;
}
}
Does anyone know how to amend our existing code to definitely avoid the Office.js has not fully loaded
error?
I recommend following the pattern that the yo office React template uses. Don't render until Office.onReady() completes. To see the entire template code, see Install the Yeoman generator — Yo Office. Run 'yo office' and then choose the React template to generate the project.