Получение введенной строки из SuggestionPickerField

Здравствуйте!
Моя задача заключается в том, чтобы реализовать функционал setNewOptionHandler из LookupField для SuggestionPickerField. Иными словами, если после ввода какой то строки, пользователю не было предложено ни одного варианта, он должен иметь возможность создать новую сущность. Сейчас это реализовано так:

streetField.setEnterActionHandler(searchString -> {          
                Addrobj newStreet = metadata.create(Addrobj.class);
                newStreet.setName(searchString);      
                streetField.setValue(newStreet);
                street = newStreet;
        });

Однако удобнее было бы вызывать подобный функционал по нажатию кнопки или отдельным действием для поля. Скажем, рядом с полем находится кнопка “Добавить”, по нажатию на которую открывался бы редактор новой сущности, куда передавалась бы написанная пользователем строка. Хотелось бы узнать, возможно ли реализовать подобное, возможно ли получить введенную пользователем строку вне контекста хэндлеров нажатия кнопки Enter или вне контекста SearchExecutor

Здравствуйте!

SuggestionPickerField не имеет API для получения результата запроса. Думаю строку для поиска можно сохранить из searchExecuter-а, однако стоит помнить, что он выполняется из другого потока (документация) и возможно стоит озаботиться синхронизацией доступа к сохраненному полю.

@Install(to = "customerField", subject = "searchExecutor")
private List<Customer> customerFieldSearchExecutor(String searchString, Map<String, Object> searchParams) {
    searchValue = searchString;

    return dataManager.load(Customer.class)
            .query("e.name like ?1 order by e.name", "%" + searchString + "%")
            .list();
}

Открытие экрана создания сущности можно реализовать через дополнительный action в SuggestionPickerField:

customerField.addAction(new BaseAction("openEditor")
        .withIcon(CubaIcon.EDIT_ACTION.source())
        .withHandler(actionPerformedEvent -> {
            CustomerEdit customerEditor = screenBuilders.editor(customerField)
                    .withScreenClass(CustomerEdit.class)
                    .newEntity()
                    .show();

            customerEditor.setSearchValue(searchValue);
            customerEditor.show();
        }), 1);

Полный пример: fsuggestion.zip (87.1 КБ)

Спасибо за развернутый ответ!
У меня только вопрос: почему у Вас 2 раза вызывается метод show()? При таком коде возникает справедливая ошибка:

Caused by: java.lang.IllegalStateException: Screen is already opened enerstroymain_Adrobject.edit
	at com.haulmont.cuba.web.sys.WebScreens.checkNotYetOpened(WebScreens.java:565) ~[cuba-web-7.1.2.jar:7.1.2]
	at com.haulmont.cuba.web.sys.WebScreens.show(WebScreens.java:423) ~[cuba-web-7.1.2.jar:7.1.2]
	at com.haulmont.cuba.gui.screen.Screen.show(Screen.java:309) ~[cuba-gui-7.1.2.jar:7.1.2]
	at com.company.enerstroymain.web.screens.addresstable.AddressTableFragment.lambda$onInit$0(AddressTableFragment.java:103) ~[ROOT-web-0.5.0.0-SNAPSHOT.jar:na]
	at com.haulmont.bali.events.EventHub.publish(EventHub.java:170) ~[cuba-global-7.1.2.jar:7.1.2]
	at com.haulmont.cuba.gui.components.actions.BaseAction.actionPerform(BaseAction.java:221) ~[cuba-gui-7.1.2.jar:7.1.2]
	at com.haulmont.cuba.web.gui.components.WebPickerField.lambda$setPickerButtonAction$0(WebPickerField.java:328) ~[cuba-web-7.1.2.jar:7.1.2]
	at com.haulmont.cuba.web.widgets.CubaButton.fireClick(CubaButton.java:76) ~[cuba-web-widgets-7.1.2.jar:na]
	at com.vaadin.ui.Button$1.click(Button.java:57) ~[vaadin-server-8.6.4-23-cuba.jar:8.6.4-23-cuba]
	... 42 common frames omitted

Если заменить первый вызов show() на build(), то в экран редактирования не передается строка поиска. Не могли бы вы вкратце пояснить, почему так происходит?
Требуемый результат возникает при удалении второго вызова метода show(). Тогда открывается экран и туда вносится значение из поисковой строки.

Это опечатка, когда правил код :slight_smile: . Да, в билдере вместо show() должен быть build() :

CustomerEdit customerEditor = screenBuilders.editor(customerField)
        .withScreenClass(CustomerEdit.class)
        .newEntity()
        .build();

customerEditor.setSearchValue(searchValue);
customerEditor.show();

Но как я уже написал, при таком коде строка не передается в экран. Все происходит корректно при следующем варианте:

CustomerEdit customerEditor = screenBuilders.editor(customerField)
        .withScreenClass(CustomerEdit.class)
        .newEntity()
        .show();

customerEditor.setSearchValue(searchValue);

Корректно ли это?

Значение проставлялось всегда, просто в некоторых случаях оно доступно на более поздних событиях жизненного цикла.

Например, когда мы использовали метод build() в билдере, то создавался экран и происходили слеующие события: InitEvent, AfterInitEvent. Т.к. мы показываем нотификацию в InitEvent, а значение устанавливаем после, то в открываемом экране searchValue = null. В этом случае если бы мы показали в AfterShowEvent, то значение было бы инициализировано (c учетом того, что searchValue само не null).

Также стоит помнить что кнопку могут нажать раньше выполнения searchExecutor.

Поправил пример: fsuggestion.zip (86.7 КБ)
Документция по жизненному циклу экранов

Спасибо за ответы!

1 симпатия