EntityPicker

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

XML-имя компонента: entityPicker.

Основы

Используйте EntityPicker, если:

  • Значение поля является ссылкой на экземпляр сущности.

  • Пользователям нужно выбрать или создать экземпляр сущности с помощью экрана выбора или ввести определенное значение.

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

По умолчанию Jmix Studio генерирует EntityPicker при создании экрана редактора сущности со ссылочным атрибутом.

entity picker1

В следующем примере экран определяет контейнер данных orderDc для сущности Order, имеющей атрибут customer. В элементе entityPicker атрибут dataContainer содержит ссылку на контейнер данных orderDc, а атрибут property ссылается на атрибут сущности customer. Этот атрибут должен быть ссылкой на сущность. В следующем примере это Customer.

<data>
    <instance id="orderDc"
              class="ui.ex1.entity.Order">
        <fetchPlan extends="_base">
            <property name="customer" fetchPlan="_instance_name"/>
        </fetchPlan>
        <loader/>
    </instance>
</data>
<layout spacing="true">
    <vbox spacing="true" id="vbox">
        <entityPicker id="customerField"
                      dataContainer="orderDc"
                      property="customer"
                      caption="msg://ui.ex1.entity/Order.customer">
            <actions>
                <action id="lookup" type="entity_lookup"/>
                <action id="clear" type="entity_clear"/>
            </actions>
        </entityPicker>
    </vbox>
</layout>

Для правильной работы EntityPicker необходимо либо задать атрибут metaClass, либо одновременно задать атрибуты dataContainer и property.

Действия

Для EntityPicker можно определить настраиваемые и предопределенные действия, отображаемые в виде кнопок справа. Это можно сделать либо в XML-дескрипторе с помощью вложенного элемента actions, либо программно в контроллере с помощью метода addAction().

Предопределенные действия

Когда Studio генерирует EntityPicker в экране редактора, она также генерирует два предопределенных стандартных действия: entity_lookup и entity_clear. Существуют также действия entity_open и entity_openComposition.

Используйте атрибуты type и id для объявления предопределенных действий в XML.

Если создать EntityPicker без действий, загрузчик XML определит для него только действия entity_lookup и entity_clear. Чтобы добавить другое предопределенное действие, например, entity_open, нужно определить элемент actions следующим образом:

<entityPicker dataContainer="orderDc"
              property="customer"
              caption="msg://ui.ex1.entity/Order.customer">
    <actions>
        <action id="lookup" type="entity_lookup"/>
        <action id="open" type="entity_open"/>
        <action id="clear" type="entity_clear"/>
    </actions>
</entityPicker>

Элемент actions не дополняет, а переопределяет набор стандартных действий. Вам необходимо явно указывать идентификаторы всех требуемых действий.

Настраиваемые действия

Чтобы определить настраиваемое действие в XML, используйте вложенный элемент actions. Укажите для action атрибуты id и icon:

<entityPicker id="customerEntityPicker"
              property="customer"
              dataContainer="orderDc">
    <actions>
        <action id="lookup" type="entity_lookup"/>
        <action id="points"
                icon="QUESTION"
                description="msg://knowPoints"/>
    </actions>
</entityPicker>

Затем реализуйте кастомную логику в контроллере экрана, подписавшись на Action.ActionPerformedEvent:

@Autowired
private EntityPicker<Customer> customerEntityPicker;
@Autowired
private Notifications notifications;

@Subscribe("customerEntityPicker.points")  (1)
public void onCustomerEntityPickerPoints(Action.ActionPerformedEvent event) {
    Customer customer = customerEntityPicker.getValue();
    if (customer != null) {
        notifications.create()
                .withCaption(customer.getFirstName() +
                        " has " + customer.getRewardPoints() +
                        " reward points")
                .show();
    } else {
        notifications.create()
                .withCaption("Choose a customer")
                .show();
    }
}
1 Аннотация @Subscribe содержит EntityPicker id и id действия, разделенные точкой.

Заглушку реализации слушателя Action.ActionPerformedEvent можно генерировать с помощью Studio.

Программное добавление действий

Используйте метод addAction() для программного задания действий.

  • Добавление стандартного действия

    Например, если компонент определен в XML-дескрипторе без вложенного элемента actions, то достаточно добавить недостающие стандартные действия:

    @Autowired
    private Actions actions;
    @Autowired
    private EntityPicker<Customer> entityPicker;
    
    @Subscribe
    public void onInit(InitEvent event) {
        entityPicker.addAction(actions.create(EntityOpenAction.class));
    }
  • Добавление настраиваемых действий

    Пример создания настраиваемого действия:

    @Autowired
    private EntityPicker<Customer> customerEp;
    
    @Subscribe
    public void onInit(InitEvent event) {
        customerEp.addAction(new BaseAction("showLevel")
                .withCaption(null)
                .withDescription(null)
                .withIcon(JmixIcon.VIEW_ACTION.source())
                .withHandler(e -> {
                    Customer customer = customerEp.getValue();
                    if (customer != null) {
                        notifications.create()
                                .withCaption(customer.getFirstName() + " " +
                                        customer.getLastName() +
                                        "'s level is " + customer.getLevel())
                                .show();
                    } else {
                        notifications.create()
                                .withCaption("Choose a customer")
                                .show();
                    }
                }));
    }

metaClass

Компонент EntityPicker можно использовать без непосредственной привязки к данным, то есть без указания dataContainer и property. В этом случае для указания типа сущности, с которой должен работать EntityPicker, используется атрибут metaClass.

<entityPicker id="custPicker" metaClass="uiex1_Customer">
    <actions>
        <action id="lookup" type="entity_lookup"/>
        <action id="open" type="entity_open"/>
    </actions>
</entityPicker>

Экземпляр выбранной сущности можно получить, инжектировав компонент в контроллер и вызвав его метод getValue().

Установка значков

Компонент EntityPicker может иметь значок слева. Просто установите fieldIconProvider в контроллере экрана для реализации кастомной логики:

@Install(to = "customerField", subject = "fieldIconProvider")
private String customerFieldFieldIconProvider(Customer customer) { (1)
    return (customer != null) ? "font-icon:CHECK" : "font-icon:BAN";
}
1 Реализация делегирующего метода fieldIconProvider.
entity picker icons

См. Значки, чтобы найти больше информации о работе со значками.

Чтобы создать провайдера иконок поля программно, используйте метод компонента setFieldIconProvider().

Ввод текстового значения

По умолчанию пользователь не может ввести значение вручную. Если задать для атрибута fieldEditable значение true, ручной ввод будет включен. Это может быть удобно для создания экземпляра сущности на основе значения, введенного пользователем.

Keep in mind that the entered value is not set to the data model. To handle user input, use the FieldValueChangeEvent.

Рассмотрим приведенный ниже пример. Дана сущность Address с атрибутом country, ссылающимся на сущность Country. Сущность Country имеет только один атрибут name. Определим countryField в XML-дескрипторе с помощью fieldEditable="true":

<entityPicker id="countryField" property="country" fieldEditable="true">
    <actions>
        <action id="lookup" type="entity_lookup"/>
        <action id="clear" type="entity_clear"/>
    </actions>
</entityPicker>

Теперь пользователь может ввести значение вручную. Для обработки этого значения как строкового, подпишитесь на FieldValueChangeEvent в контроллере:

@Autowired
private DataContext dataContext;

private Country country;

@Autowired
private TextField<String> addressField;

@Autowired
private EntityPicker<Country> countryField;

@Autowired
private Dialogs dialogs;

@Subscribe("countryField") (1)
public void onCountryFieldFieldValueChange(ValuePicker.FieldValueChangeEvent<Country>
                                                       event) {
    String value = event.getText(); (2)
    if (!Strings.isNullOrEmpty(value)) {
        country = dataContext.create(Country.class); (3)
        country.setName(value);
        countryField.setValue(country); (4)
    }
}
1 Аннотация @Subscribe содержит id EntityPicker.
2 Получение введенного значения из объекта события.
3 Создание новый экземпляр сущности Country.
4 Установка созданного экземпляра полю.

Чтобы создать слушателя события программно, используйте метод компонента addFieldValueChangeListener().

Программное создание EntityPicker

Чтобы создать EntityPicker в контроллере, используйте фабрику UiComponents. Учитывайте, что созданный программно EntityPicker не будет иметь действий по умолчанию, необходимые действия нужно определить явно:

@Autowired
private Metadata metadata;
@Autowired
private UiComponents uiComponents;
@Autowired
private Actions actions;
@Subscribe
public void onInit(InitEvent event) {
    EntityPicker<User> userPicker = uiComponents.create(EntityPicker.of(User.class));
    userPicker.setMetaClass(metadata.getClass(User.class));
    userPicker.addAction(actions.create(EntityLookupAction.class));
    userPicker.addAction(actions.create(EntityOpenAction.class));
    userPicker.addAction(actions.create(EntityClearAction.class));
    vbox.add(userPicker);
}

События и слушатели

Чтобы сгенерировать заглушку слушателя в Jmix Studio, выберите компонент в XML-дескрипторе экрана или на панели Component Hierarchy и используйте вкладку Handlers панели Component Inspector.

В качестве альтернативы вы можете воспользоваться кнопкой Generate Handler на верхней панели контроллера экрана.

ContextHelpIconClickHandler

FieldIconProvider

См. Setting Icons.

FieldValueChangeEvent

FieldValueChangeEvent отправляется, когда пользователь вручную вводит значение.

Для получения дополнительной информации см. Ввод текстового значения.

Formatter

Добавляет экземпляр formatter в компонент.

В приведенном ниже примере показано использование formatter для customerFormat:

@Install(to = "customerFormat", subject = "formatter")
protected String customerFormatFormatter(Customer value) {
    return value != null ? value.getFirstName() + " " + value.getLastName() : null;
}

Чтобы добавить formatter программно, используйте метод компонента addFormatter().

Validator

См. Validator.

ValueChangeEvent

XML-атрибуты EntityPicker

Просматривать и редактировать атрибуты, применимые к компоненту, можно с помощью панели Component Inspector конструктора экранов Studio.

XML-элементы EntityPicker