The EHR codebase includes an extensive framework for creating data entry forms. It provides a lot of baseline functionality, including:
  • Ability to compose reusable chunks of UI, such as an animal summary info panel, data entry forms, and editable grids
  • Sending data to the server for error and warning (performed by trigger scripts), and showing the user any problems that are found
  • Manage QC state transitions to track records as drafts, requests that need approval, final data, etc.
The forms are a combination of Java- and JavaScript-based code. Java code on the server sets up the configurations for forms, which are then returned to JavaScript code running in the browser that can apply additional metadata to customize the behavior and appearance, and render the UI.

Topics:

Register Java DataEntryForm Implementations

The Enter Data UI page is dynamically rendered based on the forms that are registered during server startup, combined with the current user's permissions.

Create an implementation of org.labkey.api.ehr.dataentry.DataEntryForm. Forms that support a request/fulfillment workflow typically subclass org.labkey.api.ehr.dataentry.RequestForm, and ones that wish to keep an association between a variety of different tables (such as connecting the blood draws and administered drugs that were part of a single surgery) typically subclass org.labkey.api.ehr.dataentry.TaskForm.

All implementations should be registered via a DataEntryFormFactory in their owning module's doStartupAfterSpringConfig() method via EHRService:

EHRService.get().registerFormType(new DefaultDataEntryFormFactory(MyNewFormType.class, this));

Define Java FormSection Implementations

A form is composed of one or more sections, as defined by an implementation of org.labkey.api.ehr.dataentry.FormSection. Most sections are bound to a single table in the database, typically a study dataset. Other sections simply provide instructions to the user, or show a summary of the currently selected animal.

Each section can control its layout. The most common layouts are showing a single row from a table as a series of field name/field editor pairs in a simple form layout, or showing a grid where each cell can be edited in-place.

The desired FormSection is passed through the FormType's constructor argument. A simple example that includes a form-style layout of the Task record (from ehr.tasks), a summary of the animal's info, and an editable grid section for weight data looks like:

public MyNewFormType(DataEntryFormContext ctx, Module owner)
{
this(ctx, owner, Arrays.asList(
new TaskFormSection(),
new AnimalDetailsFormSection(),
new WeightFormSection()
));
}

Include JavaScript Dependencies

Since the form is rendered in the browser using HTML and JavaScript, it's common to add customized behavior in the form of JavaScript code. These dependencies can be declared via either a FormType or a FormSection using a LabKey ClientDependency reference.

All of this JavaScript code should live under the module's ./resources/web directory.

addClientDependency(ClientDependency.fromPath("ehr/form/field/MyCustomUIElement.js"));

Common use cases for registering JavaScript code include:

  • Using a custom ExtJS store that can calculate values automatically, supply defaults, or reference values from another section of the form. In addition to the ClientDependency, configure your AbstractFormSection subclass to use it via setClientStoreClass().
  • Supplying extra metadata for the fields that are part of any section. See JavaScript Model Sources below.
  • Implementing a custom editor component. In addition to the ClientDependency, use a ConfigSource to reference your component by its registered ExtJS xtype value.
  • Supplying a custom button that acts on either a single table's editable grid or on the whole form. In addition to the ClientDependency, include your button via an override of AbstractFormSection.getTbarButtons() and register it within the JavaScript code with a call to EHR.DataEntryUtils.registerGridButton().

JavaScript Model Sources

This might hide or show fields, customize their formatting, or reference a custom ExtJS component to be used to render or edit the field.

In addition to including the JS file via a ClientDependency, configure your AbstractFormSection subclass to apply this metadata by calling setConfigSources() or addConfigSource().

The JS file can include multiple sets of configurations. Each configuration can have metadata that's applied to all tables/queries that have columns that match, and also to individual tables/queries. In the following snippet, you'll see several examples:

  • Sets all tables with a 'date' column to use a grid width of 120 pixels
  • Sets the decimal 'weight' column to allow three decimal places of precision (otherwise the default is 2 digits, meaning a value like 1.005 would be rounded to 1.01)
  • Makes the default value for the reason column in new study.drug rows have a value of 'Blood Draw'
EHR.model.DataModelManager.registerMetadata('MyCustomConfig', {
allQueries: {
date: {
columnConfig: {
width: 120
}
},
weight: {
editorConfig: {
decimalPrecision: 3
}
}
}
byQuery: {
'study.drug': {
reason: {
defaultValue: 'Blood Draw'
}
}
}
});

The full set of supported properties will depend on the ExtJS component that is rendering the value or its editor, but see the documentation for EHR.model.FieldMetadata and LABKEY.Query.FieldMetaData for the common base set.

Validation Trigger Levels

This section outlines what each validation "trigger level" means inside DataEntryUtils.js and how the UI reacts when that level is the most-severe problem in the form.

  1. INFO: Heads-up only
  2. WARN: Are you sure?
  3. ERROR: Something must be fixed (unless you're an admin)
  4. SEVERE: Hard stop

Overview

The LabKey EHR data-entry UI keeps track of the worst validation message across all grids. Each toolbar button declares two guardrails:

  • disableOn: the form automatically disables the button whenever the current max-severity is at or above this level.
  • errorThreshold: if you click the button and the max-severity is below or equal to this level, the action proceeds silently. If the Submit button is clicked and the max-severity is higher than this level, the code shows a confirmation dialog (for "ignore?") or blocks the action outright. Note that it's possible for users to bypass this dialog if they are typing fast enough and the validation is slow.
Taken together, these rules create four escalating bands of strictness. This hierarchy lets routine data issues proceed smoothly, warns about potential problems, and enforces hard stops only when data integrity is truly at risk. More detail follows this summary table.

LevelButtons that workUser experienceAdmin experience
INFOAllNo prompts; proceed freelyNo prompts; proceed freely
WARNSave Draft, Schedule, Close"Ignore warnings?" dialog on some submits"Ignore warnings?" dialog on some submits
ERRORForce Submit (admin only)Errors block until fixedCan use "Force Submit"
SEVERENoneMust fix errors before any save/submitMust fix errors before any save/submit

Review the source for DataEntryUtils.js.

INFO: Heads-up only

  • No buttons are disabled at this level.
  • Actions whose errorThreshold is "INFO" (e.g., Submit Final) require the form to be totally clean; anything higher than INFO blocks the click.
  • Typical use: non-blocking messages such as defaults filling in later or cosmetic data issues.
Net effect: Users can do anything (save draft, schedule, submit) without a prompt as long as nothing is worse than INFO.

WARN: Are you sure?

  • Disables buttons whose disableOn is "WARN": notably the regular Submit Final buttons.
  • Buttons that aren't disabled (e.g., Basic Submit) pop up a confirmation dialog asking whether to ignore the warnings.
  • Save Draft and Schedule still work because their disableOn values are higher (ERROR).
Net effect: Users can save or schedule, but finalizing the form demands either (a) fixing the warnings or (b) consciously overriding them.

ERROR: Something must be fixed (unless you're an admin)

At the Error level, the behavior differs based on whether the user has an Administrator level role in the folder.

  • Disables every standard user button whose disableOn is "ERROR" – this includes Save Draft, Schedule, and Close.
  • Only the Force Submit button (an admin-only tool) is not disabled; its own errorThreshold is "ERROR", meaning it will still run when the worst problem is an ERROR.
Net effect: Normal users are blocked from proceeding until they correct the errors; admins can override by clicking Force Submit.

SEVERE: Hard stop

  • The administrator Force Submit button is disabled because its disableOn is "SEVERE".
  • All other buttons were already disabled at ERROR, so the whole toolbar is greyed out.
Net effect: Nothing can proceed until the SEVERE issue is resolved. This is reserved for data conditions that would break system integrity or cause data loss.

Related Topics

Was this content helpful?

Log in or register an account to provide feedback


previousnext
 
expand allcollapse all