Fragments

A fragment is a UI building block that can be used as a part of views and other fragments. It’s a composite component with the following additional features:

  • Ability to define the content in XML.

  • The fragment XML element allows you to include fragments in views and other fragments declaratively.

  • The fragment class (AKA controller) supports injection of Spring beans and fragment’s UI components, as well as the use of annotated methods as handlers.

  • The ReadyEvent is sent when a fragment is fully initialized.

  • You can define actions and data components (data containers and loaders) in the fragment’s XML. Data components can be marked as provided to obtain them from the host view.

  • Studio offers the Blank fragment template to generate fragments, shows them in the Jmix tool window and allows you to use the visual designer the same as for views.

Fragments currently do not support facets.

Fragment Content

The @FragmentDescriptor annotation specifies a string value that is a path to an XML file which is used for the fragment initialization. If the value contains a file name only (and doesn’t start with /), it is assumed that the file is located in the package of the fragment class.

Elements available in the XML descriptor:

  • content - required element that contains the fragment layout (similar to the view layout element). Since the root component of a fragment can be any component, content has no attributes and doesn’t represent any component.

  • actions - optional fragment actions element (similar to the view actions element). If an action has a shortcut, it is bound to the root component of the fragment. That is, the shortcut can be triggered only if focus is within the fragment layout.

  • data - optional fragment data element (similar to the view data element). A fragment can define its own data containers and loaders or get them by id from a host view or enclosing fragment as described in the Using Data Components section.

Example of a fragment XML:

customer-list-fragment.xml
<fragment xmlns="http://jmix.io/schema/flowui/fragment">
    <data>
        <collection id="customersDc"
                    class="com.company.onboarding.entity.Customer">
            <fetchPlan extends="_base">
                <property name="city" fetchPlan="_base"/>
            </fetchPlan>
            <loader id="customersDl" readOnly="true">
                <query>
                    <![CDATA[select e from Customer e]]>
                </query>
            </loader>
        </collection>
    </data>
    <content>
        <vbox id="root" padding="false">
            <genericFilter id="genericFilter"
                           dataLoader="customersDl">
                <properties include=".*"/>
            </genericFilter>
            <hbox id="buttonsPanel" classNames="buttons-panel">
                <button id="createBtn" action="customersDataGrid.create"/>
                <button id="editBtn" action="customersDataGrid.edit"/>
                <button id="removeBtn" action="customersDataGrid.remove"/>
                <simplePagination id="pagination" dataLoader="customersDl"/>
            </hbox>
            <dataGrid id="customersDataGrid"
                      width="100%"
                      minHeight="20em"
                      dataContainer="customersDc"
                      columnReorderingAllowed="true">
                <actions>
                    <action id="create" type="list_create"/>
                    <action id="edit" type="list_edit"/>
                    <action id="remove" type="list_remove"/>
                </actions>
                <columns resizable="true">
                    <column property="city"/>
                    <column property="level"/>
                    <column property="age"/>
                    <column property="martialStatus"/>
                    <column property="hobby"/>
                    <column property="firstName"/>
                    <column property="lastName"/>
                    <column property="email"/>
                    <column property="rewardPoints"/>
                </columns>
            </dataGrid>
        </vbox>
    </content>
</fragment>

Fragment API

  • getFragmentData() - returns the FragmentData object defining methods for interacting with the fragment data components.

  • getFragmentActions() - returns the FragmentActions object defining methods for interacting with fragment actions. Similar to ViewActions.

  • getParentController() - returns a parent FragmentOwner object. Currently, it may be View or Fragment.

  • findInnerComponent() / getInnerComponent() - return the inner component with the given id. These methods search among components added via an XML descriptor only.

Fragment Events

  • ReadyEvent - the event that is fired after the fragment and all its declaratively defined inner components are created and fully initialized. In this event listener, you can make the final configuration of the fragment and its inner components. For example:

    CustomerListFragment.java
    @FragmentDescriptor("customer-list-fragment.xml")
    public class CustomerListFragment extends Fragment<VerticalLayout> {
    
        @Subscribe
        public void onReady(final ReadyEvent event) {
            getFragmentData().loadAll(); (1)
        }
    }
    1 Triggers load() method of all loaders registered in the fragment, including the provided ones.

Autowiring

Similar to views, fragments support injection of components defined in XML and invoking annotated handler methods:

@ViewComponent
public JmixButton button; (1)

@ViewComponent
public CollectionContainer<Customer> collectionDc; (2)

@Subscribe
public void onReady(ReadyEvent event) { (3)
    // ...
}

@Subscribe(value = "button", subject = "clickListener")
public void onButtonClick(ClickEvent<JmixButton> event) { (4)
    // ...
}

@Install(to = "collectionDl", target = Target.DATA_LOADER)
public List<Customer> collectionDlLoadDelegate(LoadContext<Customer> loadContext) { (5)
    return loadCustomers(loadContext);
}

@Supply(to = "dataGrid.name", subject = "renderer")
public Renderer<Customer> dataGridNameRenderer() { (6)
    return createRenderer();
}
1 Injects a UI component.
2 Inject a data container.
3 Subscribes to the fragment’s ReadyEvent.
4 Subscribes to a button’s ClickEvent.
5 Installs a load delegate.
6 Supplies a data grid Renderer.

In addition to that, it’s possible to subscribe to the host view events by defining target = Target.HOST_CONTROLLER in the @Subscribe annotation:

@Subscribe(target = Target.HOST_CONTROLLER)
public void onHostInit(View.InitEvent event) {
    // ...
}

@Subscribe(target = Target.HOST_CONTROLLER)
public void onHostBeforeShow(View.BeforeShowEvent event) {
    // ...
}

@Subscribe(target = Target.HOST_CONTROLLER)
public void onHostReady(View.ReadyEvent event) {
    // ...
}