wiki:MolgenisUiComponentsManual

Manual for Molgenis UI components

Minutes of meeting about UI components

How to make your plugin Freemarker-less

Generate your plugin the normal way but then edit the Java file and let the plugin class extend GenericPlugin instead of PluginModel. Methods getViewName() and getViewTemplate() can now go. What you get extra now is the render() method where you specify what goes on the screen when the plugin is rendered. Should you for instance have one panel containing some other UI components, you can suffice with:

public String render()
{
   return this.tablePanel.toHtml();
}

What components to choose from

In the Molgenis project, in org.molgenis.framework.ui.html, the available components can be found.

HtmlInput is the base-class for all the 'toHtml' input classes. These must implement the toHtml() method, which gives the html needed to show the component.

HtmlInput implements the Input interface. It provides the common interface as well as some convenience methods for processing the inputs. An Input has:

  • Name: unique name within a form
  • Id: a unique id of this input. FIXME remove? Name is also unique?
  • Value: the object value of the data for this input
  • Label: a pretty label to show for this input on screen
  • Readonly: indicating whether this input can be edited
  • Hidden: indicating whether this input is shown.
  • Required: whether input is required for this field.
  • Tooltip: a short title describing the input.
  • Description: a short title describing the input. FIXME: what is the difference with tooltip?
  • Style: css sentence for this input. FIXME: is this still used?

Most components have 1 constructor where you specify the name and the value.

The most important components

Buttons

  • ActionInput defines action buttons. When clicked, it will result in a new request(__action=<name>), where "name" is the name you initialized the component with. It has a type, being Save, Cancel, Next, Close, Autoclose or Custom. It has 5 constructors:
    • public ActionInput(String name): type is set to CUSTOM, label is set to type
    • public ActionInput(String name, String label): type is set to CUSTOM
    • public ActionInput(String name, String label, String buttonValue): you supply a name, a label to put in front of the button and a separate text for on the button
    • public ActionInput(String name, Type type): label is set to type
    • public ActionInput(Type select_target): name is set to type, label is set to type (replacing underscores with blanks)

Inputs

  • SelectInput: input for choosing from an pre-defined series of options. Each option is of class ValueLabel to define values and labels. The options will be shown as a dropdown select box. Its getValue() returns the label of the selected value. It has 3 constructors:
    • public SelectInput(String name, String label): value is nulled.
    • public SelectInput(String name): label is set to name, value is nulled.
    • public SelectInput(String name, Object value): label is set to name.
  • SelectMultipleInput: input for multiple select. This means that a user can select multiple items from a predefined selection. Its getValue() returns the concatenated labels of the selected values.
  • StringInput: input for string data. If it is not nillable, the class of the generated html input will be set to "required". It has 2 constructors:
    • public StringInput(String name): value is nulled
    • public StringInput(String name, Object value)
  • BoolInput: input for yes/no. If you set it to hidden, its toHtml() will return a hidden StringInput with the value (yes or no) filled in. Otherwise it will return a selectbox with two options (yes and no). You can make this component readonly, so the user cannot change it.
  • CheckboxInput: input for checkbox data. If you set it to hidden, its toHtml() will return a hidden StringInput with the current value filled in. Otherwise it will produce a series of checkboxes with the appropriate names next to them. It has 1 constructor:
    • public CheckboxInput(String name, String label, String description, Vector<ValueLabel> options, Vector<String> value). "options" contains the nice screen names for the options the user can check and "value" the corresponding underlying values.
  • DateInput: input for date. Depends on JavaScript to showDateInput(). If you set it to hidden, its toHtml() will return a hidden StringInput with the current date value filled in. Otherwise it will return an input that shows a date picker pop-up when you click it. It has 1 constructor:
    • public DateInput(String name, Object value)
  • DatetimeInput: same as DateInput, except the date string is extended with time information.
  • FileInput: input for upload of files. Its toHtml() gives the html for an input box of type "file".
  • ImageInput (extends FileInput): input for showing images. Is an extension of the FileInput with the difference that the file value is not a link but a clickable thumbnail image.
  • HiddenInput (extends StringInput): normal (string) input box that should be hidden from view. Used for hidden parameters that users don't want/need to see.
  • HyperlinkInput: input for hyperlinks. This will automatically create a hyperlink to outside information. Its toHtml() will give the code for an input box where the user can type a URL. If you then do a getValue() a html hyperlink to that URL will be returned.
  • PasswordInput: input for passwords. The password will be made unreadable. TODO: send encoded.
  • TextInput: input for strings that is rendered as a textarea. If you set it to hidden, its toHtml() will return a hidden StringInput with the value already filled in.

Reference inputs

  • XrefInput: input for cross-reference (xref) entities in a Molgenis database. Data will be shown as a selection box. Use xrefEntity to specifiy what entity provides the values for selection. Use xrefField to define which entity field to use for the values. Use xrefLabels to select which field(s) should be shown as labels to the user (optional). On focus, uses JavaScript showXrefInput to enable search-as-you-type. If you set the XrefInput to hidden, its toHtml() will return a hidden StringInput with the value already filled in.
  • MrefInput: input for many-to-many cross-references to choose data entities from the database. Selectable data items will be shown in the form of a selection box and are loaded dynamically via an 'Ajax' service. Its toHtml() generates a selectbox with the values, along with a [+] button to add an entity (using the JavaScript mref_addInput()) and a [-] button to remove an entity (using the JavaScript mref_removeInput()).

Panels

  • TablePanel: a set of inputs that are rendered together. Internally, a LinkedHashMap is used to store the inputs. Its toHtml() loops through this map and renders all the inputs in a separate div. It has 2 constructors:
    • public TablePanel(): name and label are nulled.
    • public TablePanel(String name, String label)
  • RepeatingPanel (extends TablePanel): comes with a [+] and [-] button so one can (un)repeat its contents If used in a 'label'-'value' panel the the repeatable elements will be nested into the value panel. Useful for subforms with repeating information. Features:
    • can clone itself for repeat
    • can remove clone
    • TODO set option how many clones to show at start
    • TODO set option minimum / maximum number of clones (default 0, unlimited respectively)
    • TODO set custom labels to the 'add row' and 'remove row'

Forms

  • HtmlForm: (incomplete) helper for creating forms for entities. Not to be confused with HtmlInput! EntityForm extends from this class.
  • EntityForm extends HtmlForm, optimized for showing entities. The field names within the entity are used for input names. Input creation can be influenced by setNewrecord, setHiddenColumns and setCollapsedColumns. Designed to be used with a generator to create the underlying entity class first.
  • ListView (in progress): the listview shows a list of InputForms (sets of inputs) in an Excel-like view:
    • input labels as column headers.
    • each row rending the value of the input.
    • each InputForm is assumed to have the same set of inputs.
    • each InputForm may have getActions(); those are shown in first column rendered as icon
    • if this list isSelectable (default), each row will have checkbox before each row.
    • if this list isReadonly (default) then each row will show only values, otherwise inputs
    • TODO: make easier to populate with entity instances.

Components that seem to offer no added value at this moment

  • DecimalInput (extends StringInput): input for decimal data.
  • EnumInput (extends SelectInput): input for enumerated data. Adds no extra functionality to SelectInput.
  • HexaInput (entends StringInput): input for hexadecimal data fields. It has 2 constructors:
    • public HexaInput(String name): value is set to null.
    • public HexaInput(String name, Object value)
  • IntInput (extends StringInput) input for integer data. It has 2 constructors:
    • public IntInput(String name): value is set to null.
    • public IntInput(String name, Object value)
  • LongInput (extends StringInput) input for long integer data.

Components that should not be used at the moment

  • Form (extends LinkedHashMap): status unknown and probably not in use.
  • NsequenceInput extends TextInput (incomplete): input for formatted sequences. Undocumented and untested, use not recommended.
  • OnoffInput: seems to do exactly the same as BoolInput.
  • OntologyInput (incomplete): special input to choose ontology terms from an OntoCat service. Specific OntoCat functionality seems to be missing still.
  • XrefMulticolAjaxInput (not used?): input for cross-reference (xref) data. Data will be shown as a chain of selection boxes. Each select box updates the one right next to it on change. The last one is the selection field. Seems not fully implemented, use not recommended.

Desired components

  • Progress bar
  • Table
  • Larger components with logic behind them inside a screen? I.e. shopping cart
  • Advanced xref input, with search-as-you-type and ability to add new items
  • Generic conditional input logic (if I click on 'A', I want 'C', 'D', and 'E' to show, if I click on 'B' I want 'G' to show.) I.e. hide/show/modify input/options from a select box. This can already be achieved (see below), but it would be nice to hide the JavaScript trickery from the user entirely.

How to integrate the components into your plugin

In your plugin's reload() method, say something like:

if (tablePanel == null) { // you only have to do this once
    populateTablePanel(db);
}

tablePanel is a member variable declared as follows:

public TablePanel tablePanel = null;

In the populateTablePanel() method you instantiate the panel and make a few screen components, for instance:

tablePanel = new TablePanel(this.getName() + "panel", null);

species = new SelectInput("species");
species.setLabel("Species:");
species.setOptions(ct.getAllMarkedGroups("Species"), "id", "name");
species.setNillable(false);

addbutton = new ActionInput("Add", "", "Add animal(s)");

And then you add the components to the panel:

tablePanel.add(species);
tablePanel.add(addbutton);

The class's render() method calls the toHtml() of our tablePanel, which in turn calls the toHtml()s of its components.

In your handleRequest() you can have the values of the inputs set according to the request:

String action = request.getAction();
//under the hood this is equal to request.getString("__action");
if (action.equals("Add")) { // The name of the ActionInput that was clicked
    tablePanel.setValuesFromRequest(request);
    handleAddRequest(db, request);
}

And in this handleAddRequest() method you can easily extract what the user filled in or selected, e.g.:

String speciesName = species.getValue();

Fancy JavaScript actions

You can still do fancy JavaScript tricks with your new plugin. You can for instance give a panel a specific ID:

gmoPanel = new TablePanel("GMO", "Genotype(s):");
gmoPanel.setId("GMO");

And then you can add a JavaScript onchange handler to another component:

animaltype = new SelectInput("animaltype");
// Fill it with options
animaltype.setOnchange("showHideGenotypeDiv(this.value);");

Finally, inline or in a separate script file you specify what this does to our "GMO" component (show/hide):

function showHideGenotypeDiv(animalType) {
    if (animalType == "B. Transgeen dier" && document.getElementById("GMO").style.display == "none") {
        document.getElementById("GMO").style.display = "block";
    } else {
	document.getElementById("GMO").style.display = "none";
    }
}

Code example

source:/gcc/trunk/handwritten/java/plugins/addanimal/AddAnimalPlugin.java