OfficeDev / office-js

A repo and NPM package for Office.js, corresponding to a copy of what gets published to the official "evergreen" Office.js CDN, at https://appsforoffice.microsoft.com/lib/1/hosted/office.js.
https://learn.microsoft.com/javascript/api/overview
Other
676 stars 95 forks source link

Content control events work inconsistently across Word environments #4351

Open whekin opened 6 months ago

whekin commented 6 months ago

Content control events work differently and inconsistently in Word for Mac. The behavior of onDataChanged event doesn't meet specified behavior in the docs (in Word for Mac)

Your Environment

Expected behavior

Content Control events work consistently across environments without skipping events and much delay.

Current behavior

onDataChanged content control event works differently in web and on the Mac. In the web it triggers on each key stroke with some debounce. While on Mac it works just same as onExited event. So, for consistency I tried using onExited event. And it turned out that it may not be called when working with content controls "quick". By "quick" I mean spending less than 1-2 seconds editing a content control which I believe is normal. Thus, it's possible to modify the content of a control without triggering any events except onDataChanged (once in Word for Mac, and a couple times in Word Online).

Checkboxes are inconsistent as well. In Word for Mac when working "slowly" it calls OnEnter/OnExit/OnSelectionChanged callbacks. OnDataChange also works similar to OnExit. While World Online only calls OnDataChange callbacks after a bit of delay. Though when clicking a bit away from the checkbox, it reveals the content control's title, and then it fires OnEnter/OnExit/OnSlectionChanged

Skipping calling event callbacks also happens for Office.context.document.addHandlerAsync(Office.EventType.DocumentSelectionChanged, callback) in Word for Mac. The delay of this event is also much bigger than in the Word Online.

Steps to reproduce

Just logging events can reveal the issue: ` Office.context.document.addHandlerAsync(Office.EventType.DocumentSelectionChanged, async () => "Global selection changed");

Word.run(async (context) => {
  const contentControls = context.document.getContentControls({
      types: [Word.ContentControlType.richText, Word.ContentControlType.plainText, Word.ContentControlType.checkBox],
  });

  contentControls.load("id, tag, text, type, placeHolderText");

  await context.sync();

  contentControls.track();

  contentControls.items.forEach((control) => {
    control.onEntered.add(async (event: Word.ContentControlEnteredEventArgs) => console.log("Entered", event));
    control.onExited.add(async (event: Word.ContentControlEnteredEventArgs) => console.log("Exited", event));
    control.onDataChanged.add(async (event: Word.ContentControlEnteredEventArgs) =>
      console.log("DataChanged", event),
    );
    control.onSelectionChanged.add(async (event: Word.ContentControlEnteredEventArgs) =>
      console.log("Selection Changed", event),
    );

    control.track();
  });`

Context

Maintaining the state of content controls in the Add-In has become challenging due to this issue.

microsoft-github-policy-service[bot] commented 6 months ago

Thank you for letting us know about this issue. We will take a look shortly. Thanks.

whekin commented 6 months ago

I think throttling some selection events if user moves cursor fast and doesn't change any content should be okay. But when using it for content controls' state synchronization in a Add-In it may lead to undetected changes. In web, an implementation using "DocumentSelectionChanged" to watch content control changes using selection.parentContentControlOrNullObject works just perfect.

stevefengjin commented 6 months ago

@whekin thanks for bringing this to our attention, our engineer has started looking into this issue and will provide resolution as soon as possible. Meanwhile, I would greatly appreciate it if you could provide further insights on this issue from a business perspective. Initially, while I fully understand that inconsistency between the web and desktop versions is inherently problematic and requires a permanent solution, we would like to delve deeper into the specific pain points experienced by both you and your users. Have you implemented any temporary workarounds to ensure a consistent experience for your users? If not, could you provide an estimate of the number of users affected by this inconsistency and the potential economic impact it has had? Your input will greatly assist us in assessing the full impact of the issue.

whekin commented 6 months ago

@stevefengjin I use content controls for document automation. User can edit them in a document and changes get saved to their profiles. Content controls also can be filled from data in their profile.

Content control events are new, so initially I used data bindings to add event listeners. Though adding listeners worked very slowly. We have forms that may contain hundreds of content controls in them. Bindings' addHanderAsync was called for all bindings at once, but for some reason, it executed synchronously under the hood, which was taking forever (minutes).

The implementation that listens to changes using selection change event worked well in web, but in desktop it wasn't quite reliable because of throttling. New onDataChanged event worked well in desktop though, it never throttled. Though as I mentioned it worked just like onExit, though consistently in desktop. I tried to use onExit in web, and onDataChanged in desktop, though it turned out that onExit throttled in web too. So, the final workaround is to use selection changed in web, and onDataChanged in desktop. Though if desktop Word gets fixed, I'd need to switch to onExit event.

I'm not aware of economic impact, but we had users who complained about having issues using our add-in

shanshanzheng-dev commented 5 months ago

Hi @whekin. Thanks for letting us know this issue, we have raised a internal bug #8945384 to track the process. Any update will post here!

jipyua commented 4 months ago

hi @whekin, would you please help clarify more about the error behavior you see with onExit event? You mentioned that "So, for consistency I tried using onExited event. And it turned out that it may not be called when working with content controls "quick". By "quick" I mean spending less than 1-2 seconds editing a content control which I believe is normal." Is the issue similar as post https://github.com/OfficeDev/office-js/issues/4492?

whekin commented 4 months ago

@jipyua I checked #4492, the issue is similar - the onExit event may not occur even though the user actually exited the control, in this case with arrow keys. I originally was testing only using cursor to exit a content control. Nevertheless I think the root of the issue might be the same, so possibly, if #4492 has been fixed, it could mean exiting with cursor now is stable too

jipyua commented 4 months ago

Thanks @whekin for your confirm! if this is the case, then I assume the only behavior mismatch is the onDataChanged event between online and desktop. And by using the onExit event after the bug fixed, you will be unblocked. Is this right?

whekin commented 4 months ago

@jipyua Well, my workaround seems to working fine. Once onExit works predictably across platforms I could use it for a cleaner solution. If onDataChanged gets fixed in the Mac Word, it would mean a breaking change for the workaround, so I'd have to add a check for a version when it was fixed

whekin commented 3 months ago

It tuns out, in one case onDataChanged actually works as it should, particularly when the content control is entire table cell. OnExited trigger events only sometimes in this case as well. Here's the ooxml below.

<w:sdt>
  <w:sdtPr>
    <w:tag w:val="Value On Valuation Date - hj8wi"/>
    <w:id w:val="1832791531"/>
    <w:lock w:val="sdtLocked"/>
    <w:placeholder>
      <w:docPart w:val="2F3F096242EEB24DA194B1679DBE34E1"/>
    </w:placeholder>
    <w:text/>
  </w:sdtPr>
  <w:sdtContent>
    <w:tc>
      <w:tcPr>
        <w:tcW w:w="1418" w:type="dxa"/>
        <w:shd w:val="clear" w:color="E5E5E5" w:fill="E5E5E5"/>
      </w:tcPr>
      <w:p w14:paraId="220B034F" w14:textId="77777777" w:rsidR="00FB5A11" w:rsidRDefault="00C32B78" w:rsidP="00B00372">
        <w:pPr>
          <w:pStyle w:val="Tabletext"/>
        </w:pPr>
        <w:r>
          <w:t>$444.00</w:t>
        </w:r>
      </w:p>
    </w:tc>
  </w:sdtContent>
</w:sdt>