Facets in Fragments

Fragments support the same facet mechanism as views. You can use framework-provided facets inside fragments to add reusable functionality. For a general introduction to facets, see Facets.

The following facets are available for use in fragments:

  • timer – creates a client-side timer that can trigger periodic actions.

  • fragmentSettings – saves UI component settings for a specific user.

  • fragmentDataLoadCoordinator – controls how data is loaded into the fragment.

  • urlQueryParameters – persists the state of UI components in the URL.

For example:

<fragment xmlns="http://jmix.io/schema/flowui/fragment">
<!-- some code -->
    <facets>
        <timer id="timer" delay="1000" autostart="true" repeating="true"/>
        <fragmentSettings auto="true"/>
        <fragmentDataLoadCoordinator auto="true"/>
        <urlQueryParameters>
            <dataGridFilter component="usersDataGrid"/>
            <pagination component="simplePagination"/>
            <propertyFilter component="propertyFilter"/>
            <genericFilter component="genericFilter"/>
        </urlQueryParameters>
    </facets>
    <content>
        <!-- some code -->
    </content>
</fragment>

Some facets require the fragment to have an ID. You can set it either in XML using the id attribute, or programmatically in the view controller.

settings-fragment-view.xml
<view xmlns="http://jmix.io/schema/flowui/view"
      title="msg://fragmentsettingsfragmentview.title">
    <layout>
        <details id="xmlFacetDetails"
                 summaryText="XML Facet"
                 opened="true"
                 width="100%">
            <fragment id="xmlFragment"
                      class="com.company.onboarding.view.fragments.settingsfragment.SettingsFragment"/> (1)
        </details>
        <details id="javaFacetDetails"
                 summaryText="Java Facet"
                 opened="true"
                 width="100%"/>(2)
    </layout>
</view>
1 Include the fragment in a view using the fragment element with the class attribute specifying the fragment class FQN, and the id attribute that will be set to the fragment.
2 The details layout for programmatically defining the fragment in the view controller.

The same fragment can be created programmatically using the Fragments bean. The ID is set in the create() method:

SettingsFragmentView.java
import com.company.onboarding.view.fragments.settingsfragment.SettingsFragment;
import com.company.onboarding.view.main.MainView;
import com.vaadin.flow.router.Route;
import io.jmix.flowui.Fragments;
import io.jmix.flowui.component.details.JmixDetails;
import io.jmix.flowui.view.*;
import org.springframework.beans.factory.annotation.Autowired;

@Route(value = "settings-fragment-view", layout = MainView.class)
@ViewController(id = "SettingsFragmentView")
@ViewDescriptor(path = "settings-fragment-view.xml")
public class SettingsFragmentView extends StandardView {
    @ViewComponent
    private JmixDetails javaFacetDetails;
    @Autowired
    private Fragments fragments; (1)

    @Subscribe
    public void onInit(final InitEvent event) {
        SettingsFragment javaFragment = fragments.create(this, SettingsFragment.class, "javaFragment"); (2)
        javaFacetDetails.add(javaFragment); (3)
    }
}
1 Injects the Fragments bean which is used to create fragments.
2 Creates the fragment instance using its controller class and an ID that will be set to the fragment.
3 Adds the fragment instance to the details layout component.

Timer Facet

The timer facet creates a client-side timer element. It uses the same implementation as the view-level timer, so all properties and events work the same in fragments.

Fragment XML example:

timer-fragment.xml
<fragment xmlns="http://jmix.io/schema/flowui/fragment">
    <facets>
        <timer id="timer" delay="1000" repeating="true" autostart="true"/>
    </facets>
    <content>
        <vbox id="root">
            <textField id="displayField" readOnly="true"/>
        </vbox>
    </content>
</fragment>

Fragment controller example:

TimerFragment.java
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import io.jmix.flowui.component.textfield.TypedTextField;
import io.jmix.flowui.facet.Timer;
import io.jmix.flowui.fragment.Fragment;
import io.jmix.flowui.fragment.FragmentDescriptor;
import io.jmix.flowui.view.Subscribe;
import io.jmix.flowui.view.ViewComponent;

@FragmentDescriptor("timer-fragment.xml")
public class TimerFragment extends Fragment<VerticalLayout> {
    @ViewComponent
    private TypedTextField<String> displayField;

    private int tick;

    @Subscribe("timer")
    public void onTimerTimerAction(final Timer.TimerActionEvent event) {
        displayField.setValue("Timer tick: " + tick++);
    }
}

Fragment Settings Facet

The fragmentSettings facet saves settings for visual components. Saving occurs when the view is closed, similar to the setting facet for views.

A fragment using fragmentSettings must have an ID. You can set it in XML or programmatically.

Key differences from view settings:

  • Settings are applied at the HostView.ReadyEvent event in the fragment lifecycle (instead of ReadyEvent for views).

  • This ensures settings are applied at the latest possible moment in both view and fragment lifecycles.

  • Each fragment on a view stores its own separate set of settings.

  • A dedicated XML tag fragmentSettings is used.

Fragment XML example:

settings-fragment.xml
<fragment xmlns="http://jmix.io/schema/flowui/fragment">
    <data>
        <collection id="usersDc"
                    class="com.company.onboarding.entity.User">
            <fetchPlan extends="_base"/>
            <loader id="usersDl" readOnly="true">
                <query>
                    <![CDATA[select e from User e order by e.username]]>
                </query>
            </loader>
        </collection>
    </data>
    <facets>
        <fragmentSettings auto="true"/>
        <fragmentDataLoadCoordinator auto="true"/>
        <urlQueryParameters>
            <pagination component="pagination"/>
        </urlQueryParameters>
    </facets>
    <content>
        <vbox id="root">
            <details id="details" summaryText="Nested details">
                <avatar abbreviation="Jmix"/>
            </details>
            <genericFilter id="genericFilter"
                           dataLoader="usersDl">
                <properties include=".*"/>
            </genericFilter>
            <simplePagination id="pagination" dataLoader="usersDl"
                              itemsPerPageVisible="true" itemsPerPageItems="1, 2, 5, 10"/>
            <dataGrid id="usersDataGrid"
                      width="100%"
                      columnReorderingAllowed="true"
                      minHeight="20em"
                      dataContainer="usersDc">
                <columns resizable="true">
                    <column property="username" filterable="true"/>
                    <column property="firstName" filterable="true"/>
                    <column property="lastName" filterable="true"/>
                    <column property="email" filterable="true"/>
                    <column property="timeZoneId" filterable="true"/>
                    <column property="active" filterable="true"/>
                </columns>
            </dataGrid>
        </vbox>
    </content>
</fragment>

Fragment controller example:

SettingsFragment.java
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import io.jmix.flowui.fragment.Fragment;
import io.jmix.flowui.fragment.FragmentDescriptor;

@FragmentDescriptor("settings-fragment.xml")
public class SettingsFragment extends Fragment<VerticalLayout> {
}

Fragment Data Load Coordinator Facet

The fragmentDataLoadCoordinator facet controls data loading within a fragment. For example, you can set a loading trigger on specific fragment lifecycle events.

Available lifecycle events for fragments:

  • Fragment.ReadyEvent

  • HostView.InitEvent

  • HostView.BeforeShowEvent

  • HostView.ReadyEvent

The rest of the functionality works the same as the dataLoadCoordinator facet for views.

Fragment XML example:

data-load-coordinator-fragment.xml
<fragment xmlns="http://jmix.io/schema/flowui/fragment">
    <data>
        <collection id="usersDc"
                    class="com.company.onboarding.entity.User">
            <fetchPlan extends="_base"/>
            <loader id="usersDl" readOnly="true">
                <query>
                    <![CDATA[select e from User e order by e.username]]>
                </query>
            </loader>
        </collection>
    </data>
    <facets>
        <fragmentDataLoadCoordinator auto="true"/>
    </facets>
    <content>
        <vbox id="root">
            <details id="details" summaryText="Nested details">
                <avatar abbreviation="Jmix"/>
            </details>
            <genericFilter id="genericFilter"
                           dataLoader="usersDl">
                <properties include=".*"/>
            </genericFilter>
            <simplePagination id="pagination" dataLoader="usersDl"
                              itemsPerPageVisible="true" itemsPerPageItems="1, 2, 5, 10"/>
            <dataGrid id="usersDataGrid"
                      width="100%"
                      columnReorderingAllowed="true"
                      minHeight="20em"
                      dataContainer="usersDc">
                <columns resizable="true">
                    <column property="username" filterable="true"/>
                    <column property="firstName" filterable="true"/>
                    <column property="lastName" filterable="true"/>
                    <column property="email" filterable="true"/>
                    <column property="timeZoneId" filterable="true"/>
                    <column property="active" filterable="true"/>
                </columns>
            </dataGrid>
        </vbox>
    </content>
</fragment>

Fragment controller example:

DataLoadCoordinatorFragment.java
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import io.jmix.flowui.fragment.Fragment;
import io.jmix.flowui.fragment.FragmentDescriptor;

@FragmentDescriptor("data-load-coordinator-fragment.xml")
public class DataLoadCoordinatorFragment extends Fragment<VerticalLayout> {
}

Url Query Parameters Facet

The urlQueryParameters facet persists component state in the URL. This is useful when using the URL-first approach – leaving and returning to a view preserves information like filter states.

The fragment must have an ID, as its value is used for serialization. You can set the ID in XML or programmatically.

The working principle is similar to the urlQueryParameters facet for views.

Fragment XML example:

url-query-parameters-fragment.xml
<fragment xmlns="http://jmix.io/schema/flowui/fragment">
    <data>
        <collection id="usersDc"
                    class="com.company.onboarding.entity.User">
            <fetchPlan extends="_base"/>
            <loader id="usersDl" readOnly="true">
                <query>
                    <![CDATA[select e from User e order by e.username]]>
                </query>
            </loader>
        </collection>
    </data>
    <facets>
        <fragmentDataLoadCoordinator auto="true"/>
        <urlQueryParameters>
            <propertyFilter component="propertyFilter"/>
            <genericFilter component="genericFilter"/>
            <dataGridFilter component="usersDataGrid"/>
            <pagination component="pagination"/>
        </urlQueryParameters>
    </facets>
    <content>
        <vbox id="root">
            <propertyFilter id="propertyFilter" property="username" operation="CONTAINS" dataLoader="usersDl"/>
            <genericFilter id="genericFilter"
                           dataLoader="usersDl">
                <properties include=".*"/>
            </genericFilter>
            <simplePagination id="pagination" dataLoader="usersDl"
                              itemsPerPageVisible="true" itemsPerPageItems="1, 2, 5, 10"/>
            <dataGrid id="usersDataGrid"
                      width="100%"
                      columnReorderingAllowed="true"
                      minHeight="20em"
                      dataContainer="usersDc">
                <columns resizable="true">
                    <column property="username" filterable="true"/>
                    <column property="firstName" filterable="true"/>
                    <column property="lastName" filterable="true"/>
                    <column property="email" filterable="true"/>
                    <column property="timeZoneId" filterable="true"/>
                    <column property="active" filterable="true"/>
                </columns>
            </dataGrid>
        </vbox>
    </content>
</fragment>

Fragment controller example:

UrlQueryParametersFragment.java
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import io.jmix.flowui.fragment.Fragment;
import io.jmix.flowui.fragment.FragmentDescriptor;

@FragmentDescriptor("url-query-parameters-fragment.xml")
public class UrlQueryParametersFragment extends Fragment<VerticalLayout> {
}