enketo-express icon indicating copy to clipboard operation
enketo-express copied to clipboard

Improved iframe integration

Open punkch opened this issue 1 year ago • 1 comments

I had a use case where a specific form field in the mobile app was fed by the field users by scanning a QR code. However, for the web form counterpart, there is no possibility in enketo for barcode scanning, so I've needed a way around this limitation. Luckily the system that integrates with enketo and central, is showing the webforms in an iframe and it already "knew" the possible values for this QR code field, so I've opted to improve on the iframe functionality in order to be able to set this QR code via an iframe message from the parent window.

What this PR does, is to first add a new event called 'forminitialized'. This new event is fired when the webform is successfully loaded. In addition, enketo will post messages to the parent window for all the events, rather than just SubmissionSucces, Edited and Close. This eventually allows for tighter integration between both applications. The third, and probably the biggest change this PR adds is a listener to the window message event. Messages from the parent window should be objects with just type and content property. Type is something like a command, while content is an object with shape specific to the message type. At the moment, the handler will only react to messages of type 'setfields'. Their content should be key-value pairs of the field paths and the URI encoded values to set. I've tried my best to document this in the new method's jsdoc. At the end, what my parent application now does is to wait for the 'forminitialized' event and then post the 'setfields' message for that QR code field, where the value is selected via lookup in the 'parent' system.

Closes #

I have verified this PR works with

  • [x] Online form submission
  • [ ] Offline form submission
  • [ ] Saving offline drafts
  • [ ] Loading offline drafts
  • [ ] Editing submissions
  • [x] Form preview
  • [ ] None of the above I could only verify this with form previews and online form submission as these are the only parts I am using enketo for at the moment.

What else has been done to verify that this works as intended?

Why is this the best possible solution? Were any other approaches considered?

I was trying to set default values in the form via url parameters, but it wouldn't allow for further interactions after the form was loaded. Also the pull request I've sent in this regard created some unexpected regressions.

How does this change affect users? Describe intentional changes to behavior and behavior that could have accidentally been affected by code changes. In other words, what are the regression risks?

I've done my best to isolate these changes for when only enketo is loaded in an iframe and there is parentWindowOrigin configured in the settings. In addition messages posted to the enketo window and are not from the expected origin will be ignored. Also, I've only tested this with "text" input fields, but I think that the method I am using form.input.setVal(inputDomElement, someValue) should work for any widgets.

Do we need any specific form for testing your changes? If so, please attach one.

No, this should work with any form. Here is some sample code on how to set the a form field named "Location_Id" with value "Some Location->123456-789->{8e071d7c-5829-477c-b1fb-c67cbfd64894}"

var locationName = encodeURIComponent('Some Location-\x3e123456-789-\x3e{8e071d7c-5829-477c-b1fb-c67cbfd64894}');
var message = {type:'setfields', content:{'/data/Location_Id':locationName}};
webform.postMessage(message);

Thank you very much for your time and consideration and let me know if I can somehow make this better.

punkch avatar Aug 17 '22 08:08 punkch

Well, I could probably do just with DOM access, but the iframe integration was already there (with very limited functionality) so I thought to improve it.

  • The new FormInitialized event would signal that enketo is fully done processing the webform which would be a bit later than the DOM load. So I could end up changing a field and enketo to blank it out a bit later.
  • Posting messages for all events (rather than specific few) to the parent window, opens room for tighter integration. i.e do something in the parent app on DataUpdate
  • Using the form felt as the most future proof way to change a field value in enketo.

punkch avatar Oct 21 '22 09:10 punkch