Tabsheet lazy loading example with data data containers

Hello

Can some please direct me to tabsheet lazy tab loading example with data containers? I have checked Master-Detail form by enabling lazy flag for child tabs, that also loads childs on selecting record from table.

I have to develop a screen for an entity with around 11 children and grandchildren tables which will be very heavy and slow without lazy loading.

The following example shows how to display Orders on a lazy tab of the Customer master-detail screen.
The data model is as usual: Order has a many-to-one reference to Customer.

<window xmlns="http://jmix.io/schema/ui/window"
        xmlns:c="http://jmix.io/schema/ui/jpql-condition"
        caption="msg://customerBrowse.caption"
        focusComponent="table">
    <data>
        <collection id="customersDc"
                    class="com.company.demo.entity.Customer">
            <fetchPlan extends="_base"/>
            <loader id="customersDl">
                <query>
                    <![CDATA[select e from Customer e]]>
                </query>
            </loader>
        </collection>
        <instance id="customerDc"
                  class="com.company.demo.entity.Customer">
            <fetchPlan extends="_base"/>
            <loader/>
        </instance>
        <!-- this is lazily loaded data -->
        <collection id="ordersDc" class="com.company.demo.entity.Order">
            <fetchPlan extends="_base"/>
            <loader id="ordersDl">
                <query><![CDATA[select e from Order_ e where e.customer = :customer]]></query>
            </loader>
        </collection>
    </data>
    <facets>
        <!-- remove automatic loading -->
<!--        <dataLoadCoordinator auto="true"/>-->
        <screenSettings id="settingsFacet" auto="true"/>
    </facets>
    <!-- ... -->
    <layout>
           <!-- ... -->
            <vbox id="editBox" height="100%" margin="false,false,false,true" expand="tabSheet" spacing="true">
                <tabSheet id="tabSheet">
                    <tab id="mainTab" caption="Main" margin="true">
                        <scrollBox id="fieldGroupBox">
                            <form id="form" dataContainer="customerDc">
                                <column width="350px">
                                    <textField id="nameField" property="name"/>
                                    <textField id="emailField" property="email"/>
                                </column>
                            </form>
                        </scrollBox>
                    </tab>
                    <tab id="ordersTab" caption="Orders" lazy="true" margin="true" expand="ordersTable">
                        <table id="ordersTable" width="100%" dataContainer="ordersDc">
                            <actions>
                                <action id="create" type="create"/>
                                <action id="edit" type="edit"/>
                                <action id="remove" type="remove"/>
                            </actions>
                            <buttonsPanel alwaysVisible="true">
                                <button id="ordersTableCreateBtn" action="ordersTable.create"/>
                                <button id="ordersTableEditBtn" action="ordersTable.edit"/>
                                <button id="ordersTableRemoveBtn" action="ordersTable.remove"/>
                            </buttonsPanel>
                            <columns>
                                <column id="num"/>
                                <column id="date"/>
                            </columns>
                        </table>
                    </tab>
                </tabSheet>
    <!-- ... -->
@UiController("Customer.browse")
@UiDescriptor("customer-browse.xml")
@LookupComponent("table")
public class CustomerBrowse extends MasterDetailScreen<Customer> {

    @Autowired
    private CollectionContainer<Customer> customersDc;
    @Autowired
    private CollectionLoader<Customer> customersDl;
    @Autowired
    private CollectionLoader<Order> ordersDl;

    private boolean ordersTabInitialized;

    @Subscribe
    public void onBeforeShow(BeforeShowEvent event) {
        // on screen opening, trigger loaders selectively
        customersDl.load();
    }

    @Subscribe(id = "customersDc", target = Target.DATA_CONTAINER)
    public void onCustomersDcItemChange(InstanceContainer.ItemChangeEvent<Customer> event) {
        // refresh data on lazy tab if it was selected by the user
        if (ordersTabInitialized) {
            refreshOrders();
        }
    }

    @Subscribe("tabSheet")
    public void onTabSheetSelectedTabChange(TabSheet.SelectedTabChangeEvent event) {
        if (event.getSelectedTab().getName().equals("ordersTab") && !ordersTabInitialized) {
            ordersTabInitialized = true;

            refreshOrders();

            // get components located on the lazy tab
            Table<Order> ordersTable = (Table) getWindow().getComponentNN("ordersTable");
            CreateAction<Order> orderCreateAction = (CreateAction) ordersTable.getActionNN("create");
            // initalize new order with current cuatomer
            orderCreateAction.setInitializer((Order order) -> {
                order.setCustomer(getEditedEntity());
            });
            // enable creating orders only for already existing customers
            orderCreateAction.addEnabledRule(() -> !creating);
        }
    }

    private void refreshOrders() {
        ordersDl.setParameter("customer", customersDc.getItemOrNull());
        ordersDl.load();
    }
}

The entire project:
demo.zip (87.9 KB)

Regards,
Konstantin

1 Like

Thanks Konstantin for detailed reply and demo project.

Calling refreshOrders() in onCustomersDcItemChange is the point here. I was unable to figure that out.