Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Related issue 

Jira
serverMagnolia - Issue tracker
columnskey,summary,type,created,updated,due,assignee,reporter,priority,status,resolution
serverId500b06a6-e204-3125-b989-2d75b973d05f
keyDEV-883

Table of Contents

Goal

We want to provide users with a simple, modern API to build arbitrarily complex fields.

Problem

All is good, as long as a simple value is bound to a simple field, e.g. TextField → String. 

...

Currently Magnolia does provide such ability through custom multi fields (see AbstractCustomMultiField) but they have several shortcomings, both in terms of internal implementation and from a client developer's perspective (see for instance 

Jira
serverMagnolia - Issue tracker
serverId500b06a6-e204-3125-b989-2d75b973d05f
keyMGNLUI-2542
).  

Proposal

  • Assume the field is simple and atomic

  • When you need to manage many related values - it is another form within a form

  • Complex fields are like forms but with stripped layout

Layouting 

Form (or editor) layout should be separated from the binding mechanism and should be flexible

...

PoC https://git.magnolia-cms.com/users/jsimak/repos/ui/pull-requests/1/commits/91980c4dbd0803b429e50f037f4b70a638cce0dd

A class diagram from the current PoC and a description of their main responsibilities

Image RemovedImage Added


FormDefinition

  • is a ComponentDefinition
  • is registered and mapped to a factory class like any other form field
  • has FieldDefinition(s)
  • has a LayoutDefinition



Code Pro
collapseTypeClassic
languageyaml
themeEmacs
titleForm configuration example (YAML)
# this is the 'main' form configuration
form:
  fields:
    title:
      class: info.magnolia.ui.form.poc.definition.TextFieldDefinition
    firstName:
      class: info.magnolia.ui.form.poc.definition.TextFieldDefinition
	lastName:
      class: info.magnolia.ui.form.poc.definition.TextFieldDefinition
    # address is a form component (a subform of the main form) and specifies its own layout.
    # It is declared under fields and we can refer to it as a field
    # see below form/layout/tabs/more/fields/address
    address:
      class: info.magnolia.ui.form.poc.definition.FormDefinition
      fields:
        city:
          class: info.magnolia.ui.form.poc.definition.TextFieldDefinition
        country:
          class: info.magnolia.ui.form.poc.definition.TextFieldDefinition
        nestedphone: # a form component can have sub-form components with their own layout
          class: info.magnolia.ui.form.poc.definition.FormDefinition
          fields:
            quxareaCode:
              class: info.magnolia.ui.form.poc.definition.TextFieldDefinition
			number:
          layout:
            class: info.magnolia.ui.form.poc.layoutdefinition.MyLayoutTextFieldDefinition
            fieldslayout:
              qux:class: info.magnolia.ui.form.poc.layout.MyLayout	
      layout: # this is the layout for address
        class: info.magnolia.ui.form.poc.layout.DefaultLayoutDefinition
        fields:
          city:
          country:
          nested:
  # this is the main form's layout configuration
  # layout configurations could probably be omitted altogether and rely on a reasonable default 
  layout:
    class: info.magnolia.ui.form.poc.layout.TabbedLayoutDefinition
    tabs:
      personal:
        fields:
          title:
          firstName:
		  lastName:	
      more:
        fields:
          # address is a form component (a subform of the main form)
          # here it is referred to as if it were a plain Field
          address:


LayoutDefinition

  • has a list of field names composing the layout. Their names match those of the FieldDefinition(s)
  • specifies LayoutProducer implementation class


LayoutProducer

  • is instantiated from a LayoutDefinition
  • createLayout(LayoutDefinition, Map<String, Component>) creates the actual layout (a Vaadin Component) from
    • LayoutDefinition
    • a mapping of field names and actual field components

Form

  • is a plain Java class

  • it stores
    • its Binder
    • its own Layout (including sub-form layouts)
    • its sub-forms
  • can save and validate self and its sub-forms recursively (should this functionality move away from Form?) 

FormPresenter

  • is currently the orchestrator of the form building process
  • creates the final form view (a Vaadin Layout)
    • instantiates a Form from a FormDefinition
    • returns the form view to the caller



Code Pro
languagejava
themeEmacs
titleSnippet from FormPresenter
collapsetrue
...
 /***
 * @return a {@link View} as described by this {@link FormDefinition} including nested forms, if any.
 */
public View createFormView(D formDefinition) {
    FormView view = new FormView();
    Form<T> form = formFactory.createForm(formDefinition);
    view.addComponent(form.getLayout());

    return view;
}


TODO

We now have the basic infrastructure to build and bind form components (including arbitrarily nested, complex sub-forms). We . Layout is split from field definitions. We can also read and write them forms and sub-forms without the need for special transformers.

What is left to do. 

  • Form
    • styling
    • set labels, help messages and descriptions: use something like info.magnolia.ui.dialog.formdialog.FormView?

    • update forms/fields based on Locale? See info.magnolia.ui.dialog.formdialog.FormPresenterImpl.updateForm()

    • pass FormPresenter to DetailPresenter(..) which takes care of initializing actions and other stuff before calling and setting the form view?

  • Fields
    • implement them or harden the ones which we began to implement (TextField, SelectField)
    • populating select options based on the value of another field
    • validating a field depending on the value of another field (including within a composite field itself)
    • enabling/disabling fields conditionally
    • potentially custom handling of any field, via plain Vaadin code
    • properly highlighting validation on sub-fields (this should be already taken care of by Vaadin, only need proepr error field styling).
  • FormBinder/FormContext
    • currently saving a new item fails cause the node id we get is null.
    • current implementation relies on JcrNodeItemid and JcrNewNodeItemId: not sure we want to use them
  • Layout
    • naming
    • Custom layout impl doesn't work
    • provide a Vaadin declarative layout impl
    • In case of resource-based layout we could and should provide flt support (i.e. pre-process the script before binding to the fields)