O3: Embedding "Conditions Widget" in Forms

Hi all,

Extending discussion from: Proposing “Form Embeddable Widgets”:

In OMRS, form-engine technologies primarily focus on capturing observational data, however we have other data points that in a POC setting are captured from different parts of the framework eg. Allergies, Conditions etc. It’s important to note that these are all patient centric data points. At UCSF we plan to grab some of the existing widgets and embed them within forms.

OpenMRS 2.x support of embeddable widgets

The ancient/legacy OpenMRS had this notion of portlets, were modules had the ability of defining their own portlets and could be re-used within other JSPs.

2.x on the other hand has the UI Framework, which introduced the concept of UI Fragments. A more practical example could be the EncounterDiagnoses widget. This is available in HFE forms but defined within coreapps as a UI Framework fragment. It’s independent of the forms-engine and has a built-in mechanism of posting and fetching data to the backend. I believe this same widget can be used in other parts of the framework.


Happy talking about O3?

O3 has this concept of extensions(Learn more about extensions). An Extension simply wraps a Component(hypothetically agnostic to any framework) within some-kind of special parcel that can mounted at any declared slot in the application. Any basic micro-frontend can declare slot and define extensions declaratively or imperatively.

Downscoping

O3 already has support for capturing patient conditions. This widget(actually a simple static form) is readily available as an Extension. You just have to add the required MF(@ openmrs/esm-patient-conditions-app) to your import-map.

However, we just can’t embed this widget as-is within any form as it’s published as a form itself with the “Cancel” and “Save” controls at the bottom.

As a POC, we are happy to spike on refactoring this to a widget that can be smoothly embedded in an existing form. Below are my thoughts, your thoughts are welcome to help draft a better mind map:

  • Currently the widget is fused with standard forms controls, I think we should break this down so that the actual widget is independent of the form it lives in.
  • For this to work, the widget should have a built-in mechanism to handle submission by itself. This could either be more explicit through callbacks or through events? Or we could fuse small adhoc controls within the widget(could be config driven?) that trigger submission? Your input on this would really be helpful.

cc: @bistenes, @jdick, @mksd, @dkibet, @mayanja, @eudson, @grace

6 Likes

Hi @samuel34 , it sounds like you’re on the right track. I don’t know what the best way to handle data submission for form sub-components is. I think that’s a big unsolved problem in form engine design.

Wouldn’t it be simpler to start with a widget that does not handle server data submission? A widget that just displays data passed to it, and collects data entered by the user, passing it over to the parent. Just like a calendar or date picker widget.

Having components of a form with side effects breaks the contract of the form – e.g., you can change things without ever submitting the form.

I think you’re suggesting that the ability of the condition widget to submit changes itself be made optional.

My recommendation would be to remove the form submission from the widget and then refactor the other place(s) the widget is used to handle the submission or, if there are multiple places, create a separate “condition form” widget that wraps the condition widget in a little form. Those places that want to let users make direct/immediate changes to conditions can use the condition form and any form would just use the condition widget.

1 Like

Ampath forms has support for embeddable widgets. Widgets are expected to be wrapped as standard web components and should be fully self-contained. cc: @achachiez

I’m inclined to having a paradigm where the form engine is able to publish a “form:submission” kind of event to “embedded” widget(s) so that the widgets perform submissions when the form is submitted.

Of-course this could be optional.

1 Like

thanks @samuel34 for that clarification , I kindly provide an opinion for splitting this issue into some simple tickets .

Filed ticket at: [O3-1298] Conditions as an "embeddable" widget - OpenMRS Issues

1 Like

ICYMI: @samuel34 updated the O3 Squad on last week’s squad call about the progress on this work.

Demo video from Samuel Male (UCSF) - Embedding Conditions Widget in a form: Microfrontend Meeting - Indiana University

Relevant PR here: Extract a "conditions widget" out of the conditions-forms by samuelmale · Pull Request #708 · openmrs/openmrs-esm-patient-chart · GitHub

Screenshot of the Condition Widget actually being embedded in a form!

2 Likes

Thanks @grace for updating this thread. We are thinking on supporting recording of multiple conditions at once, as you can see the widget only supports recording of one currently and our BA team (@wamz @mwaririm) think that such feature will be a good addition.

2 Likes

Perfect - I completely agree, 100%.

I imagine we could apply @pauladams’ past designs for Presenting Complaints, this is so nice and simple for adding or removing items: Zeplin - Projects

As a heads up… I’ve seen in past projects that the technical complexity can balloon if we want to also display known-conditions within the form as well (so eg the user can see oh, Diabetes Type 2 was already recorded, I don’t need to add that). I wonder if @wamz wants to add that? In the RefApp I guess the split-screen desktop view does allow the clinician to see past reported issues if the user is looking at past conditions on the left while doing the form on the right, but these would not be visible in full-screen-form-view or tablet mode. (Gets even more complicated if we want to enable a clinician to delete a past-reported condition, but I don’t think that needs to be in scope.)

1 Like

@grace for the known conditions I think validation could help in this scenario. If we agree that the same type/kind of condition cannot be added then, when the user selects a known-condition the system can block or alert the user that he/she is entering an already existing condition. How does that sound?

1 Like

Sounds perfect! <3

Hi @samuel34 and all,

I was recently thinking about how we can leverage our existing O3 components that were built standalone such that we can re-use many of the underlying components within forms. I’ve long thought that we want to ensure we can re-use the existing, richly designed components that have been built and not re-invent the wheel within the form engine. I was recently pointed to this thread and really excited to see that this has been given some thought and was implemented with conditions.

One question I have (and this extends to other aspects of o3 as well) is how data submission of embedded components is handled with respect to transactions. Assuming I’m reading the code right (and please correct me if I’m not), when a form is submitted it will hit it’s configured endpoint, and then trigger other embedded components to also submit to their endpoints. So, if a form were to contain it’s own data collection of observations, and then contain embedded components that have been built for conditions, orders, allergies, diagnoses, etc. - the resulting form submission might result in several calls to different FHIR or REST endpoints to perform the actual submission, any of which will fail or succeed independently.

My concern is that designing things in this way could lead to data submissions that are only partially successful (and could stay that way), without clear ways to indicate what has succeeded and what has failed to the end user.

One alternative that I had hoped might be considered / discussed was to have a core notion of the current encounter within the page itself. This could be either in some sort of encounter context, or passed around as a prop or whatever, but each component would be designed with the possibility that it could receive an existing encounter to operate upon, and it’s responsibility would then be to update this encounter’s state rather than submit related data independently.

The wrapping component would take responsibility for submitting this to the encounter endpoint, which would handle all aspects of that encounter data.

I’m interested in hearing others thoughts about this and how / whether we might evolve o3 to support this kind of “transactional” / contextual notion of the current encounter.

@ibacher @dennis @burke @mogoodrich @eudson

2 Likes