JSF SelectManyListbox с noSelectionOption = "true" - ошибка проверки: недопустимое значение.
У меня проблема, когда элементы заполнены POJO и истинно (для
h:selectManyListbox
с перечислениями в качестве элементов, он работает, как я ожидал).
Фасоль
@Named
@ViewScoped
public class MyBean implements Serializable {
private static final long serialVersionUID = 1L;
private List<BaseDTO> availableItems = null;
private String[] selectedItems = null;
@PostConstruct
private void initialize() {
loadAvailableItems();
}
private void loadAvailableItems() {
availableItems = Arrays.asList(new BaseDTO("entityId", "entityDescription"), new BaseDTO(...), ...);
}
public List<BaseDTO> getAvailableItems() {
return availableItems;
}
public String[] getSelectedItems() {
return selectedItems;
}
public void setSelectedItems(String[] selectedItems) {
this.selectedItems = selectedItems;
}
}
BaseDTO
public class BaseDTO {
private String id;
private String description;
public BaseDTO(String id, String description) {
this.id = id;
this.description = description;
}
public String getId() {
return id;
}
public String getDescription() {
return description;
}
@Override
public String toString() {
return id;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id.hashCode();
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
BaseDTO other = (BaseDTO) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
XHTML
<h:selectManyListbox value="#{myBean.selectedItems}" hideNoSelectionOption="false" size="4">
<f:selectItem itemValue="#{null}" itemLabel="--" noSelectionOption="true" />
<f:selectItems value="#{myBean.availableItems}" var="entry" itemValue="#{entry.id}" itemLabel="#{entry.description}" />
</h:selectManyListbox>
Когда я пытаюсь отправить страницу, я всегда получаю
Validation Error: Value is not valid
. Если я удалю
hideNoSelectionOption
и соответствующие
<f:selectItem itemValue="#{null}" itemLabel="--" noSelectionOption="true" />
все работает нормально, но мне бы очень хотелось, чтобы это было в моем списке.
Я попытался использовать OmniFaces SelectItemsConverter и даже создать свой собственный конвертер, но безуспешно. Что бы я ни пытался, я не могу преодолеть эту ошибку проверки.
Тем временем я нашел не очень приятный обходной путь:
Если мой
availableItems
переменная - это
Map<String, String>
вместо
List
:
private Map<String, String> availableItems = null;
и если я добавлю на карту нулевую запись:
private void loadAvailableItems() {
List<BaseDTO> dtoList = Arrays.asList(new BaseDTO("entityId", "entityDescription"));
availableItems = dtoList.stream().collect(Collectors.toMap(BaseDTO::getId, BaseDTO::getDescription));
availableItems.put(null, "--");
}
тогда все работает, как ожидалось, кроме
noSelectionOption
не выбран заранее на странице.
Это ожидаемое поведение компонента, или я что-то упускаю?
Заранее спасибо за помощь!
2 ответа
Прежде всего,
noSelectionOption
/
hideNoSelectionOption
Пара атрибутов была неправильно понята здесь. Пожалуйста, удалите их. В вашем контексте это совершенно бесполезно. Чтобы лучше понять их первоначальную цель, перейдите к ответу Лучший способ добавить параметр «ничего не выбрано» в selectOneMenu в JSF , который резюмируется следующим образом:
Основная цель этой пары атрибутов состоит в том, чтобы предотвратить возможность повторного выбора пользователем веб-сайта «параметра без выбора», когда для компонента уже выбрано ненулевое значение.
В вашем конкретном случае у вас есть список с множественным выбором. Во-первых, нет смысла иметь опцию «ничего не выбрано» в таком элементе пользовательского интерфейса. Вам просто нужно отменить выбор всего, чтобы иметь состояние «ничего не выбрано». Это невозможно, например, в раскрывающемся списке с одним выбором, потому что вы не можете отменить выбор выбранного параметра в первую очередь. Следовательно, такой элемент пользовательского интерфейса нуждается в опции «ничего не выбрано». Но, опять же, это не нужно для списка с множественным выбором. Однако я понимаю, что полезно иметь активный элемент, который автоматически отменяет выбор всего в списке. Это можно было сделать с помощью ссылки или кнопки рядом со списком.
В любом случае, мне удалось воспроизвести описанную проблему в Mojarra 2.3.17. Основная проблема заключается в том, что «отправленное значение пустой строки» больше не представлено пустым массивом строк, а массивом строк с одним элементом, пустой строкой. Поэтому все проверки, связанные с «отправленным значением пустой строки», впоследствии завершились неудачно. Я не думаю, что это ошибка в самом JSF, но это просто случай неожиданного использования компонента с множественным выбором.
Вы можете обойти все это, явно отключив элемент на всех этапах, кроме фазы ответа рендеринга (6-й этап). Его можно будет выбрать, но он будет автоматически удален из выбранных элементов в качестве встроенной меры защиты от фальсифицированных запросов. Таким образом, «отправленное значение пустой строки» будет пустым массивом, как и ожидалось.
<h:selectManyListbox value="#{myBean.selectedItems}" size="4">
<f:selectItem itemValue="#{null}" itemLabel="--" itemDisabled="#{facesContext.currentPhaseId.ordinal ne 6}" />
<f:selectItems value="#{myBean.availableItems}" var="entry" itemValue="#{entry.id}" itemLabel="#{entry.description}" />
</h:selectManyListbox>
Следует отметить, что это не может быть решено с помощью специального конвертера или валидатора. JSF не позволил бы пользовательскому конвертеру вернуться
null
, и эта конкретная проверка «Значение недействительно» выполняется встроенным средством проверки против поддельных запросов, которые нельзя заменить/отключить. Нашим лучшим выбором, вероятно, было бы изменить/переопределить поведение
noSelectionOption="true"
поскольку это действительно слишком часто неправильно понимают. Вероятно, с ним следует обращаться так же, как с отключенным элементом.
Похоже, он пытается проверить значение и не может. Вы пытались вместо этого использовать собственный валидатор?