Fragment 中的 Facet

Fragment 支持与视图相同的 facet 机制。可以在 fragment 内部使用框架提供的 facet 添加可复用的功能。有关 facet 的一般介绍,请参见 Facets

以下 facet 可用于 fragment 中:

  • timer – 创建一个客户端定时器,可触发周期性操作。

  • fragmentSettings – 为特定用户保存 UI 组件的设置。

  • fragmentDataLoadCoordinator – 控制数据如何加载到 fragment 中。

  • urlQueryParameters – 将 UI 组件的状态持久化到 URL 中。

示例:

<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>

某些 facet 要求 fragment 必须具有 ID。可以在 XML 中使用 id 属性设置,或者在视图控制器中以编程方式设置。

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 在视图中使用 fragment 元素引入 fragment,通过 class 属性指定 fragment 类的全限定名,并通过 id 属性设置 fragment 的 ID。
2 在视图控制器中以编程方式定义 fragment 的一个 details

可以使用 Fragments bean 以编程方式创建相同的 fragment。ID 在 create() 方法中设置:

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 注入用于创建 fragment 的 Fragments bean。
2 使用控制器类和将要设置给 fragment 的 ID 创建 fragment 实例。
3 将 fragment 实例添加到 details 布局组件中。

Timer Facet

timer facet 创建一个客户端侧的定时器元素。其实现与视图级别 timer 相同,因此所有的属性和事件也在 fragment 中支持。

Fragment XML 示例:

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 控制器示例:

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

fragmentSettings facet 用于保存可视化组件的设置。保存操作在视图关闭时进行,类似于视图的 setting facet。

使用 fragmentSettings 的 fragment 必须具有 ID。可以在 XML 中或以编程方式 设置。

与视图 setting 的主要区别:

  • Settings 在 fragment 生命周期中的 HostView.ReadyEvent 事件时应用(而不是视图的 ReadyEvent)。

  • 这可以保证 Settings 在视图和 fragment 生命周期的尽可能晚的时刻被应用。

  • 视图上的每个 fragment 都会存储自己独立的一套设置。

  • 使用专用的 XML 标签 fragmentSettings

Fragment XML 示例:

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 控制器示例:

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

fragmentDataLoadCoordinator facet 用于控制 fragment 内的数据加载。例如,可以在特定的 fragment 生命周期事件上设置加载触发器。

Fragment 可用的生命周期事件:

  • Fragment.ReadyEvent

  • HostView.InitEvent

  • HostView.BeforeShowEvent

  • HostView.ReadyEvent

其余功能与视图的 dataLoadCoordinator facet 相同。

Fragment XML 示例:

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 控制器示例:

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

urlQueryParameters facet 将组件状态持久化到 URL 中。有助于使用 URL 优先的方式:离开后返回视图时,可以保留过滤器状态等信息。

fragment 必须具有 ID,因为其值用于序列化。可以在 XML 中或以编程方式 设置。

其工作原理与视图的 urlQueryParameters facet 类似。

Fragment XML 示例:

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 控制器示例:

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> {
}