1
votes

Within Office.js, specifically Excel, you can add/register Event Handlers (which are technically Promises). So for instance, Microsoft's documentation gives this example:

await Excel.run(async (context) => {
    let sheet = context.workbook.worksheets;
    sheet.onAdded.add(onWorksheetAdd);

    await context.sync();
    console.log("A handler has been registered for the OnAdded event.");
});

I am currently working in Angular though so I want to "wrangle" all this async code into observable to have some sense of control over everything happening on the Excel document. In the above example, we are listening to when User adds a new Worksheet. onWorksheetAdd will register that Event Handler so that when the User executes the action (adding a new worksheet), the onWorksheetAdd callback/promise will be called.

Below is what I currently have.

excel-worksheet.service.ts

registerOnAddWorksheetHandler() {
        return from(
            // @ts-ignore
            Excel.run((context) => {
                    let sheet = context.workbook.worksheets;
                    sheet.onAdded.add(this.excelEventHandlerService.onAddWorksheetHandler) ; // must pass Promise as argument

                    console.log("A handler has been registered for the OnAdded event.");
                }
                return context.sync();
            })
        );
    }

excel-event-handler.service.ts

 onAddWorksheetHandler(event): Promise<any> {
        return of(
            // @ts-ignore
            Excel.run((context) => {
                    console.log("Handler for worksheet onAdded event has been triggered. Newly added worksheet Id : " + event.worksheetId, event);

                return context.sync();
            })
        )
        .toPromise()
    }

Essentially, what I want is to wrap the event handler in an Observable so that my app.component.ts can register the information to my application.

I have tried the following:

  • Within onAddWorksheetHandler, I have attempted to continue to resolve the Promises. By that I called .then() after context.sync(), followed by calling it again on Excel.run(), followed by calling it after toPromise(). This is unsuccessfully though because registerOnAddWorksheetHandler has registered the event and won't have access to it's value. Mainly because Office.js is Promise based so execution is one and done.
  • I have tried declaring a Subject on excel-event-handler.service.ts so that app.component.ts can have access but that also failed. I'm not sure if the event handler registered is swallowing anything trying to be bubbled up.

My last effort to try to resolve this is just to move those registered event handlers to app.component.ts to have access to the scope. I was hoping to have done this a bit more elegantly.

1

1 Answers

0
votes

This was an misunderstanding on my end.A case of not seeing the forest for the trees. For office.js event handlers, you only need to execute the Excel.run() and the context.sync() command in order to actually just register <some_callback()>.

Excel.run((context) => {
  let sheet = context.workbook.worksheets;
  sheet.onAdded.add(<some_callback()>);
  return context.sync();
})

Where my confusion laid was I assumed that whole Excel.run() dance had to all be executed within the <some_callback()>. Turns out it does not, you can have that just be your typical JS callback. Within Angular, that can be any method from the component that needs to be executed. Same logic would apply with any other framework.

I hope this helps others.