Versions Compared

Key

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

...

  • 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 striped layout.

Layouting 

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

  • first, we produce the field/sub-form components and bind them to the binder

  • then we pass the mapping of e.g. the property names and the resulting components (fields/sub-forms) to a layout producer

    • LayoutProducer the layout producer could yield a tabbed layout that we have currently or any other type of layout based on the configured definition

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

Class diagramImage Modified










FormFormDefinition-

  • is a
component, same as a field
- during its building process it stores
-- a mapping of field names and resulting field components
-- a LayoutDefinition
- exposes mappings + LayoutDefinition via functional interface
e.g. form.attachToLayout((layout, mappings) -> doLayout(layout, mapping))
- attachToLayout internally takes care of creating the main form layout
and all subforms' layouts (if any)
  • ComponentDefinition
  • is registered and mapped to a factory class like any other form field
  • has FieldDefinition(s)
  • has a LayoutDefinition
FormViewFactory
- creates a FormView (a Vaadin Layout)
-- instantiates a Form from a FormDefinition
-- instantiates a LayoutProducer
-- calls form.attachToLayout(..) and passes mappings + LayoutDefinition to the LayoutProducer



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
    name:
      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
        nested: # a form component can have sub-form components with their own layout
          class: info.magnolia.ui.form.poc.definition.FormDefinition
          fields:
            qux:
              class: info.magnolia.ui.form.poc.definition.TextFieldDefinition
          layout:
            class: info.magnolia.ui.form.poc.layout.MyLayout
            fields:
              qux:
      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:
          name:
      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 component, same as a field

  • during its building process it stores
    • a mapping of field names and resulting field components
    • it own LayoutDefinition
  • exposes mappings + LayoutDefinition via functional interface e.g. form.attachToLayout((layout, mappings) -> doLayout(layout, mapping))
  • attachToLayout internally takes care of creating the main form layout and all subforms' layouts (if any)


FormViewFactory

  • is currently the orchestrator of the whole form building process
  • creates the final form view (a Vaadin Layout)
  • instantiates a Form from a FormDefinition
  • instantiates a LayoutProducer
  • calls form.attachToLayout(..) and calls a lambda function which eventually delegates to the LayoutProducer

Code Pro
languagejava
titleSnippet from FormViewFactory
...
/***
    * @return a {@link View} as described by this {@link FormDefinition} including nested forms, if any.
    */
   public View createFormView(D formDefinition) {
       CssLayout view = new CssLayout();
       Form<T> form = createForm(formDefinition);
       Layout rootLayout = form.attachToLayout((layout, mappings) -> createLayout(layout, mappings));
       view.addComponent(rootLayout);

       return view;
   }

   protected Form<T> createForm(D formDefinition) {
       //TODO how to instantiate the correct PropertySet?
       FormFactory<D, T> formFactory = componentProvider.newInstance(FormFactory.class, formDefinition, subAppContext,
               new JcrNodePropertySet(collectFormFieldDefinitions(formDefinition), null, null), componentFactoryFactory);
       return (Form<T>) formFactory.createComponent();
   }

   protected Layout createLayout(LayoutDefinition definition, Map<String, Component> mappings) {
       LayoutProducer producer = componentProvider.newInstance(definition.getImplementationClass());
       return producer.createLayout(definition, mappings);
   }