2.5.4. Экран редактирования Покупателя со списком Заказов

Займемся задачей отображения списка заказов в окне редактирования покупателя.

Перейдите в секцию Generic UI. Откройте на редактирование экран customer-edit.xml.

Перейдите на вкладку Designer.

В группе Data components в палитре компонентов найдите Collection и перетащите его в секцию data в иерархии компонентов экрана.

Для контейнера выберите сущность com.company.sales.entity.Order и её представление _local. Сгенерируйте loader ID с помощью кнопки generate_id.

Добавьте параметр WHERE в сгенерированный запрос JPQL, чтобы загружать только те заказы, которые имеют ссылку на нужного нам покупателя:

select e from sales_Order e where e.customer = :customer

В итоге у вас должен получиться следующий data container для загрузки экземпляров сущности Order:

<data>
    <instance id="customerDc" class="com.company.sales.entity.Customer" view="_local">
        <loader/>
    </instance>
    <collection id="ordersDc" class="com.company.sales.entity.Order" view="_local">
        <loader id="ordersDl">
            <query><![CDATA[select e from sales_Order e where e.customer = :customer]]></query>
        </loader>
    </collection>
</data>

Далее, в палитре компонентов найдите компонент Label. Перетащите этот компонент на панель иерархии компонентов экрана между элементами form и editActions. Перейдите на вкладку Properties на панели свойств. В поле value введите значение компонента: Orders.

Если разрабатываемое приложение предполагает локализацию на несколько языков, используйте кнопку localization рядом с полем value, чтобы создать новое сообщение msg://orders и задать его значение на требуемых языках.

Перетащите компонент Table из палитры компонентов на панель иерархии компонентов между label и editActions. Выделите компонент в иерархии и перейдите на вкладку Properties. Задайте размеры таблицы: в поле width укажите 300px, в поле height установите значение 200px. Из списка доступных источников данных выберите контейнер ordersDc, после этого в поле id с помощью кнопки generate_id сгенерируйте идентификатор таблицы: ordersTable.

В контекстном меню таблицы выберите Wrap Into > Group Box. Перейдите на вкладку Properties контейнера groupBox на панели свойств и введите Orders в поле caption, в поле width укажите 320px.

customer edit

В итоге дескриптор экрана customer-edit.xml на вкладке Text будет выглядеть следующим образом:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd" caption="msg://editorCaption" focusComponent="form"
        messagesPack="com.company.sales.web.customer">
    <data>
        <instance id="customerDc" class="com.company.sales.entity.Customer" view="_local">
            <loader/>
        </instance>
        <collection id="ordersDc" class="com.company.sales.entity.Order" view="_local">
            <loader id="ordersDl">
                <query><![CDATA[select e from sales_Order e where e.customer = :customer]]></query>
            </loader>
        </collection>
    </data>
    <dialogMode height="600" width="800"/>
    <layout expand="editActions" spacing="true">
        <form id="form" dataContainer="customerDc">
            <column width="250px">
                <textField id="nameField" property="name"/>
                <textField id="emailField" property="email"/>
            </column>
        </form>
        <groupBox caption="Orders">
            <table id="ordersDcTable" dataContainer="ordersDc" height="200px" width="300px">
                <columns>
                    <column id="date"/>
                    <column id="amount"/>
                </columns>
            </table>
        </groupBox>
        <hbox id="editActions" spacing="true">
            <button action="windowCommitAndClose"/>
            <button action="windowClose"/>
        </hbox>
    </layout>
</window>

Откройте контроллер экрана CustomerEdit. Кнопки © и <> на панели с номерами строк помогут вам быстро переключаться между дескриптором и контроллером экрана.

Для начала давайте отключим автоматическую загрузку данных. Для этого удалите аннотацию @LoadDataBeforeShow из исходного кода.

Инжектируйте loader для заказов в класс контроллера:

@Inject
private CollectionLoader<Order> ordersDl;

Затем подпишитесь на событие BeforeShowEvent, чтобы указать значение параметра customer в запросе ordersDl. Это можно сделать, нажав Alt+Insert и выбрав Subscribe to Event в появившемся меню Generate.

@UiController("sales_Customer.edit")
@UiDescriptor("customer-edit.xml")
@EditedEntityContainer("customerDc")
public class CustomerEdit extends StandardEditor<Customer> {
    @Inject
    private CollectionLoader<Order> ordersDl;

    @Subscribe
    protected void onBeforeShow(BeforeShowEvent event) {
        ordersDl.setParameter("customer", getEditedEntity());
        getScreenData().loadAll();
    }
}

Этот метод будет загружать связанные экземпляры сущности Order.