FlowUI: What are the layout rules/tricks/tips/etc?

In most business applications, there is a need to lay out screens in a certain way, for proper flow, and for organizing of things in a way a user might think. In CUBA and Jmix, the various “box” components (hBox and vBox mostly) accomplished that fairly reliably.

Here is a fairly simple screen in Jmix classic UI:

phys-classic

To begin research on FlowUI I started trying to replicate very simple screens, and here is the same screen in FlowUI. All I did was auto-generate the screen in a Flow project, and then cut-and-paste the component code from the Classic UI version and change the names of some components and attributes (dateField to datePicker, optionsContainer to itemsContainer and so on).

Here is the resulting descriptor code:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<view xmlns="http://jmix.io/schema/flowui/view"
      title="msg://physicianDetailView.title"
      focusComponent="form">
    <data>
        <instance id="physicianDc"
                  class="com.medflex.mfflow.entity.physician.Physician">
            <fetchPlan extends="_base">
                <property name="type" fetchPlan="_base"/>
                <property name="specialty" fetchPlan="_base"/>
                <property name="salesperson" fetchPlan="_base"/>
            </fetchPlan>
            <loader/>
        </instance>
        <collection id="typesDc" class="com.medflex.mfflow.entity.physician.PhysicianType" fetchPlan="_instance_name">
            <loader id="typesLc">
                <query>
                    <![CDATA[select e from mfflow_PhysicianType e]]>
                </query>
            </loader>
        </collection>
        <collection id="specialtiesDc" class="com.medflex.mfflow.entity.physician.PhysicianSpecialty"
                    fetchPlan="_instance_name">
            <loader id="specialtiesLc">
                <query>
                    <![CDATA[select e from mfflow_PhysicianSpecialty e]]>
                </query>
            </loader>
        </collection>
        <collection id="salespersonsDc" class="com.medflex.mfflow.entity.Salesperson" fetchPlan="_instance_name">
            <loader id="salespersonsLc">
                <query>
                    <![CDATA[select e from mfflow_Salesperson e]]>
                </query>
            </loader>
        </collection>
    </data>
    <facets>
        <dataLoadCoordinator auto="true"/>
    </facets>
    <actions>
        <action id="saveAction" type="detail_saveClose"/>
        <action id="closeAction" type="detail_close"/>
    </actions>
    <layout>
        <formLayout id="form" dataContainer="physicianDc">
            <hbox spacing="true">
                <textField id="lastNameField" property="lastName" dataContainer="physicianDc"
                           label="Last name"/>
                <textField id="firstNameField" property="firstName" dataContainer="physicianDc"
                           label="First name"/>
                <textField id="titleField" property="title" dataContainer="physicianDc" 
                           label="Title"/>
            </hbox>
            <hbox>
                <textField id="address1Field" property="address1" dataContainer="physicianDc" label="Address"
                           width="200px"/>
                <label/>
            </hbox>
            <hbox>
                <textField id="address2Field" property="address2" dataContainer="physicianDc" width="200px"
                           label=" "/>
                <label/>
            </hbox>
            <hbox spacing="true">
                <textField id="cityField" property="city" dataContainer="physicianDc" width="200px"
                           label="City"/>
                <comboBox id="stateField" property="state" dataContainer="physicianDc" width="75px"
                          label="State"/>
                <textField id="zipField" property="zip" dataContainer="physicianDc" label="Zip"/>
            </hbox>
            <hbox spacing="true">
                <textField id="emailField" property="email" dataContainer="physicianDc" label="Email"/>
                <textField id="mainPhoneField" property="mainPhone" dataContainer="physicianDc"
                           label="Main phone"/>
                <textField id="faxField" property="fax" dataContainer="physicianDc" 
                           label="Fax"/>
            </hbox>
            <hbox spacing="true">
                <textField id="cellPhoneField" property="cellPhone" dataContainer="physicianDc"
                           label="Cell phone"/>
                <textField id="pagerPhoneField" property="pagerPhone" dataContainer="physicianDc"
                           label="Pager"/>
            </hbox>
            <hbox spacing="true">
                <textField id="licenseField" label="msg://licenseCaption" dataContainer="physicianDc"
                           property="license"/>
            </hbox>
            <hbox spacing="true">
                <textField id="upinField" property="upin" dataContainer="physicianDc" label="UPIN"/>
                <textField id="npiField" property="npi" dataContainer="physicianDc" label="NPI"/>
                <textField id="stateIDField" property="stateID" dataContainer="physicianDc" label="State ID"/>
            </hbox>
            <hbox spacing="true">
                <textField id="commRateField" property="commRate" dataContainer="physicianDc"
                           label="Comm. rate"/>
                <datePicker id="licenseExpDateField" property="licenseExpDate" dataContainer="physicianDc"
                           label="License exp. date"/>
            </hbox>
            <hbox spacing="true">
                <checkbox id="pecosConfirmedField" property="pecosConfirmed" dataContainer="physicianDc"
                          label="PECOS confirmed?" align="MIDDLE_CENTER"/>
                <datePicker id="pecosConfirmedDateField" property="pecosConfirmedDate"
                           dataContainer="physicianDc"
                           label="PECOS confirmed date"/>
            </hbox>
            <hbox spacing="true">
                <entityComboBox id="typeField" itemsContainer="typesDc" property="type"
                                dataContainer="physicianDc"
                                label="Type">
                    <actions>
                        <action id="lookup" type="entity_lookup"/>
                        <action id="clear" type="entity_clear"/>
                    </actions>
                </entityComboBox>
                <entityComboBox id="specialtyField" itemsContainer="specialtiesDc" property="specialty"
                                dataContainer="physicianDc"
                                label="Specialty">
                    <actions>
                        <action id="lookup" type="entity_lookup"/>
                        <action id="clear" type="entity_clear"/>
                    </actions>
                </entityComboBox>
                <entityComboBox id="salespersonField" itemsContainer="salespersonsDc" property="salesperson"
                                dataContainer="physicianDc"
                                label="Salesperson">
                    <actions>
                        <action id="lookup" type="entity_lookup"/>
                        <action id="clear" type="entity_clear"/>
                    </actions>
                </entityComboBox>
            </hbox>
            <textArea id="notesField" property="notes" dataContainer="physicianDc"
                               />
        </formLayout>
        <hbox id="detailActions">
            <button id="saveAndCloseBtn" action="saveAction"/>
            <button id="closeBtn" action="closeAction"/>
        </hbox>
    </layout>
</view>

And here is how it rendered:

phys-flow

The address-1 field ends up next to the name line, and address-2 ends up on a line with city/state/zip, instead of those on their own lines as in the classic version.

What are the rules/tricks/tips for accomplishing this layout control in FlowUI?

Hello Jon!

FormLayout is a responsive layout that allows you to manage multiple columns depending on layout’s width.

By default FormLayout has two columns and every second element in the layout will be placed in the second column. For instance:
image

We can manage how many columns will be visible using the Responsive steps:

   ...
      <responsiveSteps>
           <responsiveStep minWidth="0" columns="1"/> <!-- if form's width exceeds 0, use 1 column  -->
           <responsiveStep minWidth="20em" columns="2"/>  <!-- if form's width exceeds 20em, use 2 column  -->
      </responsiveSteps>
 </formLayout>

Due to responsive FormLayout we can build UI more friendly to devices with small screen. For more details see Form Layout | Components | Vaadin Docs

Is formLayout required or is there another way to manage things more like the “old way?”

FormLayout is not required, you can use any component layout or even HTML components like div, etc.
The main thing is that fields are should be bound with DataContainer and property.

FormLayout and Form (in classic UI) simplify binding data with fields, managing labels and displays fields in columns.