Using CodedConceptDatatype

We need to create a Provider Attribute type that uses a concept to display a list of possible answers. e.g. Education Level. I have noticed there is a new customdatatype.CodedConceptDatatype added to the coreapps and I was wondering if I could use it when creating and rendering a Provider Attribute? Please see below an example on how we used this new custom data type. Please let us know if there is a better, more general way of doing this. Thanks.

The short answer is that what you’re doing here is not the general preferred way, but we don’t actually have any modern examples that do the preferred way.

The original idea, from the time of OpenMRS 1.9 is that:

  • Attributes must have a CustomDatatype, and they may optionally further specify a CustomDatatypeHandler
  • CustomDatatype does the UI-independent side of things, i.e. how to read/write the value from the database or external storage, and how to format it for simplistic display.
  • CustomDatatypeHandler is the generic idea of a UI-specific handler, but the UI technology in question would need to be more specific about this.
  • openmrs-core also defined some pretty-generic subinterfaces (HtmlDisplayableCustomDatatypeHandler and DownloadableDatatypeHandler), but these were moved to the legacyui module (probably a mistake)
  • Specific UI applications should define abstract base classes or interfaces to represent the types of widgets that they know how to render, and a dev would extend these to implement the kind of UI widget that would work within that application. For example the old openmrs-web (now moved to legacyui) had FieldGenDatatypeHandler and WebDatatypeHandler, and this part of the UI layer was specifically coded to support those.

So, the correct way to do what you’re doing here would be:

  1. In uicommons (or uiframework) introduce an abstract class or interface FragmentIncludeCustomDatatypeHandler

  2. In uicommons introduce a fragment like “valueForSingleCustomField” which is equivalent to the singleCustomValue.tag file I linked above

  3. In uicommons:

    • DateFragmentCustomDatatypeHandler (which does the ui.includeFragment that’s in your snippet)
    • CodedConceptFragmentCustomDatatypeHandler (move the elseif block from your code into a fragment and this class would include that)
  4. then in your module you just do something like

    attributes.each { a -> ${ ui.includeFragment(“uicommons”, “valueForSingleCustomField”, [ attribute: a, …]) } }

Whether you actually want to do all this the right way depends on how much investment you want to be making in uiframework-backed UIs.

So to make sure I understand @darius, using the “CodedConceptDatatype” makes sense, and isa general way of doing this from a data/API level, the question is whether we want to go through the further effort of creating interfaces in the UI Framework to support editing/displaying that data type, versus using the quick else-if branch that @cioan created to just handle the edit/display in the location we need it?

Take care, Mark

Thanks @darius for explaining how all those components were supposed to work.

Yes Mark, exactly that.

-Darius (by phone)

Cool, great. @cioan I’d say if you feel ambitious go ahead and implement what Darius suggests, but it’s not worth it if it seems like a lot of work… definitely something we can put off/never do.

Mark