Saving observations using custom tag handler

I have successfully created a custom tag handler for HTML forms. Which saves the observations for my module but if we add another observation like as simple as HEIGHT

   <section headerLabel="1. Encounter Details">
		<table class="baseline-aligned">
			<tr>
				<td>Date:</td>
				<td><encounterDate default="today"/></td>
			</tr>
			<tr>
				<td>Location:</td>
				<td><encounterLocation/></td>
			</tr>
			<tr>
				<td>Provider:</td>
				<td><encounterProvider/></td>
			</tr>
		</table>
	</section>

    <obs conceptId="5090" labelText="Height"/>

	<CustomTag />

	<submit/>

This saves the observation from my module since I’m using REST API. But its not saving the HEIGHT.

Is there something else I need to do?

@darius @dkayiwa

I guess there must be a bug in your custom tag. Can you share a link to the code?

Sure.

class DrawingEditorElement implements FormSubmissionControllerAction, HtmlGeneratorElement {
		
		UiUtils uiUtils;
		
		DrawingEditorElement(UiUtils uiUtils) {
			this.uiUtils = uiUtils;
		}
		
		@Override
		public Collection<FormSubmissionError> validateSubmission(FormEntryContext context, HttpServletRequest submission) {
			
			return null;
		}
		
		@Override
		public void handleSubmission(FormEntrySession session, HttpServletRequest request) {
			
		}
		
		@Override
		public String generateHtml(FormEntryContext context) {
			
			StringBuilder sb = new StringBuilder();
			try {
				sb.append(uiUtils.includeFragment("drawing", "editor"));
				return sb.toString();
			}
			catch (PageAction pageAction) {
				throw new IllegalStateException("Included fragment threw a PageAction", pageAction);
			}
		}
	}

I’m not performing any validation since the observation is a canvas. Also, I’m handling the submission through REST controller, so I didn’t implement validateSubmission and handleSubmission methods.

What does the drawing/editor fragment look like? (Ideally you’d share a link to github, as opposed to pasting it all.)

Some things you can do to debug this:

  1. Use your browser’s js console to inspect the DOM of the form. Note the name of the html element (something like “w7”). Then when you submit the form, make sure that value was submitted in the POST. (If not perhaps your custom javascript is interfering with it somehow.)
  2. Attach a java debugger check out htmlformentry or htmlformentryui and put a breakpoint here: https://github.com/openmrs/openmrs-module-htmlformentryui/blob/master/omod/src/main/java/org/openmrs/module/htmlformentryui/fragment/controller/htmlform/EnterHtmlFormFragmentController.java#L202 then check to see what’s being submitted.
  3. (The toughest option would be to debug the ObsSubmissionElement.handleSubmission method and see what’s going on there.)

Here,

Github Link

Please let me know if you have any questions regarding the code.

This code is almost certainly wrong

    beforeSubmit.push(function() {
        $("#status-save").click();
        setTimeout(function (e) {
            return true;
        }, 3000);
    });

You are trying to say “trigger a click (which will be handled in another thread), then wait 3 seconds and return true” but JavaScript is single-threaded and doesn’t work that way.

This ties back to something I said on another thread: Custom encounter in patinet dashboard

The correct way to approach this is to update the underlying HTML Form Entry code so that it allows beforeSubmit functions to return Promises, and waits for the promises to resolve before actually submitting the form.

(Sorry I don’t have time to go into more depth; I’m not aware of any other way to get your js code, which depends on asynchronous events, to play nicely with HFE.)

Sure. No problem.

I’ll check with HFE and get back to you with update.

Thanks.

To try to be a bit more helpful here, off the top of my head I think the task is something like:

  • Include a promise polyfill in HTML Form Entry to ensure backwards-compatibility with older browsers [can do this step last]
  • Need to edit files in both htmlformentryui and htmlformentry so it works in both the legacy ui and the reference application.

The code might look something like this (but you’d have to write it in older-style JS):

var promises = beforeSubmit.map(userDefined => Promise.resolve(userDefined()));
Promise.all(promises).then(results => {
    // loop over results array. if all results are true, then call htmlForm.submitHtmlForm()
},
error => {
    // do something
});

so