# HFE: Validating forms

**URL:** <https://talk.openmrs.org/t/hfe-validating-forms/31448>\
**Category:** Add-on Modules\
**Tags:** html-form-entry, validation, htmlform\
**Created:** [December 22, 2020, 12:19pm UTC](https://talk.openmrs.org/t/hfe-validating-forms/31448 "2020-12-22T12:19:37Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![mksd](https://talk.openmrs.org/user_avatar/talk.openmrs.org/mksd/32/11729_2.png) [@mksd](https://talk.openmrs.org/u/mksd)\
**Post date:** [December 22, 2020, 12:19pm UTC](https://talk.openmrs.org/t/hfe-validating-forms/31448/1 "2020-12-22T12:19:37Z")

</div>

Hey @mseaton,

(Continuing here our discussions about validating HFE forms, as [here](https://openmrs.slack.com/archives/C010NJS2AM7/p1606171340024300) on Slack for one of them.)

I am not sure where the form validation should happen exactly, maybe optionally just before [here](https://github.com/openmrs/openmrs-module-htmlformentry/blob/569d00ca86cc918d7e294c91e04e1e0e0725fa25/api/src/main/java/org/openmrs/module/htmlformentry/impl/HtmlFormEntryServiceImpl.java#L141) in `HtmlFormEntryServiceImpl#saveHtmlForm`.

Anyway my idea was to do something like that:

```java
void validateForm(HtmlFormEntryService service, HtmlForm form) throws Exception {
    Document doc = HtmlFormEntryUtil.stringToDocument(form.getXmlData());
    
    Map<Node, TagValidator> validators = new HashMap<>();
    addTagValidators(service, HtmlFormEntryUtil.findChild(doc, "htmlform"), validators);
    
    validators.keySet().stream().forEach(node -> {
        validators.get(node).validate(node);
    });
}

```

Where basically I crawl through the nodes to get their `TagValidator`, and then validate each node.

As for the recursive `addTagValidators` it would look like this:

```java
void addTagValidators(HtmlFormEntryService service, Node node, final Map<Node, TagValidator> validators) {
    
    TagHandler handler = service.getHandlerByTagName(node.getNodeName());
    
    if (handler != null) {
        if (handler instanceof TagValidator) {
            validators.put(node, (TagValidator) handler);
        }
        else {
            // unfortunately a handler leading to no validator
        }
    }
    
    NodeList list = node.getChildNodes();
    for (int i = 0; i < list.getLength(); ++i) {
        addTagValidators(service, list.item(i), validators);
    }
}

```

Does that make sense to you?

FYI this is syntactically correct code but I haven’t even tried it, I just pulled bits here and there taking a lot of inspiration from [`applyTagsHelper`](https://github.com/openmrs/openmrs-module-htmlformentry/blob/07d07f9edcdf56711c341766e4406e8c0bf62110/api/src/main/java/org/openmrs/module/htmlformentry/HtmlFormEntryGenerator.java#L592). I just wanted to kick start the topic and leave a trace for picking this up again next year 😉

---

<div class="post-metadata">

**Author:** ![mksd](https://talk.openmrs.org/user_avatar/talk.openmrs.org/mksd/32/11729_2.png) [@mksd](https://talk.openmrs.org/u/mksd)\
**Post date:** [February 10, 2021, 4:37pm UTC](https://talk.openmrs.org/t/hfe-validating-forms/31448/2 "2021-02-10T16:37:47Z")

</div>

Hi [@AMPATH](https://talk.openmrs.org/groups/ampath) team / @jdick, bouncing back on the same topic regarding AMPATH forms. Is there any mechanism - be it front or backend - for the forms to expose which metadata they require to function?

---

<div class="post-metadata">

**Author:** ![achachiez](https://talk.openmrs.org/user_avatar/talk.openmrs.org/achachiez/32/2049_2.png) [@achachiez](https://talk.openmrs.org/u/achachiez)\
**Post date:** [February 10, 2021, 10:19pm UTC](https://talk.openmrs.org/t/hfe-validating-forms/31448/3 "2021-02-10T22:19:18Z")

</div>

@mksd am probably giving the wrong answer 😀 . But we made an attempt to ensure the renderer just worked without any special configurations in openmrs. If you take a look at [ngx-openmrs-formentry/adult-1.4.json at master · AMPATH/ngx-openmrs-formentry · GitHub](https://github.com/AMPATH/ngx-openmrs-formentry/blob/master/src/app/adult-1.4.json) the schema carries pretty much everything the renderer need to render the form and generate an encounter payload. This means it will render anything as long as it is a valid schema. Whether you are able to save the form correctly though depends on whether the metadata you used in the form actually exists in openmrs. The renderer require the implementer to inject a data service which provides data that may be needed to do validations and skip logic.

---

<div class="post-metadata">

**Author:** ![mksd](https://talk.openmrs.org/user_avatar/talk.openmrs.org/mksd/32/11729_2.png) [@mksd](https://talk.openmrs.org/u/mksd)\
**Post date:** [February 11, 2021, 9:12pm UTC](https://talk.openmrs.org/t/hfe-validating-forms/31448/4 "2021-02-11T21:12:52Z")

</div>

Thanks @achachiez. I was expecting something along those lines and I think it makes sense, from a UX standpoint, to facilitate rendering (even if some referenced metadata is invalid/missing… etc.)

Could you point me to the place in the AMPATH forms project where the form is saved, along with its version… etc? So when the `Form` object is persisted.

---

<div class="post-metadata">

**Author:** ![achachiez](https://talk.openmrs.org/user_avatar/talk.openmrs.org/achachiez/32/2049_2.png) [@achachiez](https://talk.openmrs.org/u/achachiez)\
**Post date:** [February 12, 2021, 1:08pm UTC](https://talk.openmrs.org/t/hfe-validating-forms/31448/5 "2021-02-12T13:08:23Z")

</div>

Starting here we provider services for fetching remote data [ngx-openmrs-formentry/app.component.ts at 737603144c49eb8194d7326b19bc23433c076d6d · AMPATH/ngx-openmrs-formentry · GitHub](https://github.com/AMPATH/ngx-openmrs-formentry/blob/737603144c49eb8194d7326b19bc23433c076d6d/src/app/app.component.ts#L56) In this case we are mocking the services but in the main project they actually fetch data from openmrs. Starting here we [ngx-openmrs-formentry/app.component.ts at 737603144c49eb8194d7326b19bc23433c076d6d · AMPATH/ngx-openmrs-formentry · GitHub](https://github.com/AMPATH/ngx-openmrs-formentry/blob/737603144c49eb8194d7326b19bc23433c076d6d/src/app/app.component.ts#L152) We create the form

Here we populate orders [ngx-openmrs-formentry/app.component.ts at 737603144c49eb8194d7326b19bc23433c076d6d · AMPATH/ngx-openmrs-formentry · GitHub](https://github.com/AMPATH/ngx-openmrs-formentry/blob/737603144c49eb8194d7326b19bc23433c076d6d/src/app/app.component.ts#L155)

Here we populate an encounter as returned from the encounter resource.[ngx-openmrs-formentry/app.component.ts at 737603144c49eb8194d7326b19bc23433c076d6d · AMPATH/ngx-openmrs-formentry · GitHub](https://github.com/AMPATH/ngx-openmrs-formentry/blob/737603144c49eb8194d7326b19bc23433c076d6d/src/app/app.component.ts#L156)

This [ngx-openmrs-formentry/app.component.ts at 737603144c49eb8194d7326b19bc23433c076d6d · AMPATH/ngx-openmrs-formentry · GitHub](https://github.com/AMPATH/ngx-openmrs-formentry/blob/737603144c49eb8194d7326b19bc23433c076d6d/src/app/app.component.ts#L237) is called on submit and generates a payload, at this point you just call the service to save the encounter. Here is the component of Ampath POC that consumes it [ng2-amrs/formentry.component.ts at master · AMPATH/ng2-amrs · GitHub](https://github.com/AMPATH/ng2-amrs/blob/master/src/app/patient-dashboard/common/formentry/formentry.component.ts)
