Have you implemented OpenMRS? Please participate in the Implementation Site Survey. If you already have, thank you!
Page tree
Skip to end of metadata
Go to start of metadata

The UI Framework code is being transitioned to a module. Documentation will move to UI Framework.

Summary

When writing a fragment that goes on patient pages, you should follow all these best practices, so that the fragment works consistently with all the others.

Level 1 - For all fragments
  • Use the utility method to get the Patient from the PageModel or FragmentConfiguration
  • If the data you are going to display is easily available, then draw it all on page load without AJAX
    • Doing AJAX calls on page load is a performance-killer over high-latency satellite connections.
    • You should use AJAX for intensive calculations that would significantly slow down the initial page draw
  • Don't decorate yourself. Allow the consumer that is calling you to choose your decoration.
  • Wrap a div with an id around the entire visible area of your fragment
    • allow the consumer to set that id (in groovy: def id = config.id ?: ui.randomId("prefix")
Level 2 - Fragments that can refresh via AJAX
  • Remember that even if your fragment is capable of refreshing itself via AJAX, it must draw itself without any AJAX calls on page load.
  • Your fragment should refresh itself (fetch data from the server, and redraw) on the "YOUR-FRAGMENT-ID.refresh" message
  • If you modify any patient data, you should publish a message like "patient/patientId/relationships.changed". (See below for messages we've defined so far.) This message must contain a standard javascript object representing the patient as its payload.
    • Ideally you can return this object as the JSON response from your fragment action on success.
    • Alternately you may call the patientChanged(patientId, property) function (from openmrs.js), which will fetch the patient from the server and then publish "patient/patientId/category.changed". (This is easier, but requires an extra server round-trip.)
  • Your fragment should also refresh itself on any of these messages: (see below for the payloads of these messages)
    • person/personId.changed
    • patient/patientId.changed
    • person/personId/yourproperty.changed (if 'yourproperty' is on Person as opposed to Patient)
    • patient/patientId/yourproperty.changed (if 'yourproperty' is on Patient)

Details

controller() method

Patient fragments should typically work on the patient from the shared PageModel, but the consumer should be able to override that by providing a patient or patientId in the FragmentConfiguration. You should start your controller fragment by calling the utility method FragmentUtil.getPatient(PageModel, FragmentConfiguration).

Standard messages

Message

Meaning

Promised Content

person/personId.changed

One or many unspecified properties of the person have changed

Standard javascript person object with TBD properties

patient/patientId.changed

One or many unspecified properties of the patient have changed

Standard javascript patient object with TBD properties

person/personId/names.changed

Names have been added, edited, removed, or preferred

personId, names[] (with uuid, givenName, middleName, familyName, familyName2, preferred)

person/patientId/addresses.changed

Addresses have been added, edited, removed, or preferred

personId, addresses[] (with uuid, address1, address2, ..., preferred)

patient/patientId/identifiers.changed

Identifiers have been added, edited, removed, or preferred 

patientId, activeIdentifiers[] (with id, identifierType*, identifier, location*, preferred)

* = OpenmrsMetadata will be typically returned as an object with id and label properties

  • No labels

5 Comments

  1. The standard here is going to change.

    1. messages about a Person will be "person/personId/names.changed" while messages about a Patient will be "patient/patientId/identifiers.changed".

    2. Instead of having each event include the same standard javascript patient object, each event will include a minimal person or patient object which always includes the patientId, and the property that has changed, and optionally includes other properties. So for example adding a patient identifier might send

    {
        patientId: 1234, // guaranteed
        activeIdentifiers: [ ... ], // guaranteed
        personName: "Darius Jazayeri", // optional
    }

    Further, I plan to introduce a "DTO" class, which is the equivalent of the "Ref" object in our proposed web services design. Basically instead of just passing a string back for things like PatientIdentifierType, we'll pass back

    {
        class: "org.openmrs.PatientIdentifierType",
        id: 1,
        label: "Medical Record Number"
    }

    A nice feature of doing things this way is that we'll be able to use Spring type conversion to convert things to DTO, which will let us get rid of the ObjectResult.build utility method.

    TODO:

    • move parts of this comment into ticket
    • revise the page itself
    1. It is good that you decided to resign from the standard javascript patient object. I like the optionality in the new approach much better.

      I don't entirely understand the trick with DTO. How will the DTO class look like? Will I have to write it for each type I want to handle this way?

      1. The reasoning is that

        1. we don't want to blindly serialize a possibly-lazy-possibly-cyclical hibernate object to send over the wire
        2. It's not always enough to just send pretty-formatted strings over the wire.
          1. For example I want us to have widgets that display a location, concept, etc, as a nicely-formatted display name, but also with a link to more information via ajax+popup.

        Something like:

        • DTO extends LinkedHashMap<String, Object>.
        • We'd have default OpenmrsMetadataToDTOConverter and OpenmrsDataToDTOConverter
        • So for metadata that wants to be displayed as its "name" property, you don't have to write a specific DTO converter

        I think it will take me less time to code this up 25% of the way than it will take to describe it in detail...

        1. You are right. There is no need to go in detail. I am looking forward to see the code. Your reasoning is promising.

          1. Check out the comments and patch on TRUNK-2226, and let me know what you think.