Як використовувати значення enum у f: selectItem (s)


103

Я хочу зробити спадне меню selectOneMenu, щоб я міг вибрати статус у своєму питанні. Чи можна зробити f: selectItem більш гнучким, враховуючи, що станеться, якщо порядок перерахунків зміниться, і якщо список великий? І я міг би зробити це краще? І чи можливо автоматично "вибрати" предмет, який має питання?

Енум клас

public enum Status {
    SUBMITTED,
    REJECTED,
    APPROVED
}

Питання суб'єкта

@Enumerated(EnumType.STRING)
private Status status;

JSF

<div class="field">
    <h:outputLabel for="questionStatus" value="Status" />
    <h:selectOneMenu id="questionStatus" value="#{bean.question.status}" >
        <f:selectItem itemLabel="Submitted" itemValue="0" />
        <f:selectItem itemLabel="Rejected" itemValue="1" />
        <f:selectItem itemLabel="Approved" itemValue="2" />
    </h:selectOneMenu>
    <hr />
</div>

Відповіді:


210

JSF має вбудований перетворювач для enum, тому для цього слід:

@ManagedBean
@ApplicationScoped
public class Data {

    public Status[] getStatuses() {
        return Status.values();
    }

}

з

<h:selectOneMenu value="#{bean.question.status}" >
    <f:selectItems value="#{data.statuses}" />
</h:selectOneMenu>

(Примітка: з JSF 2.0 немає необхідності більше , щоб забезпечити SelectItem[]або List<SelectItem>, T[]і List<T>приймається , а також і ви можете отримати доступ до поточного елементу з допомогою varатрибута)

Якщо ви випадково використовуєте бібліотеку утиліт JSF OmniFaces , тоді ви можете використовувати <o:importConstants>замість бобів.

<o:importConstants type="com.example.Status" />

<h:selectOneMenu value="#{bean.question.status}" >
    <f:selectItems value="#{Status}" />
</h:selectOneMenu>

Якщо ви також маєте право контролювати етикетки, ви можете додати їх до Statusпереліку:

public enum Status {

    SUBMITTED("Submitted"),
    REJECTED("Rejected"),
    APPROVED("Approved");

    private String label;

    private Status(String label) {
        this.label = label;
    }

    public String getLabel() {
        return label;
    }

}

з

<f:selectItems value="#{data.statuses}" var="status"
    itemValue="#{status}" itemLabel="#{status.label}" />

Або, краще, зробіть значення enum ключем властивості локалізованого пакета ресурсів (необхідний EL 3.0):

<f:selectItems value="#{data.statuses}" var="status"
    itemValue="#{status}" itemLabel="#{text['data.status.' += status]}" />

з цим у файлі властивостей, пов'язаному з пакетом ресурсів #{text}

data.status.SUBMITTED = Submitted
data.status.REJECTED = Rejected
data.status.APPROVED = Approved

Одне, BalusC, чи можна "вибрати" / переглянути стан, який має запитання за замовчуванням (наприклад, коли ви редагуєте запитання, тоді ви вже встановили статус питання на щось)
LuckyLuke

У наведеному вище прикладі JSF зробить це за замовчуванням, коли #{bean.question.status}має дійсне значення перерахунку. Вам не потрібно нічого робити, щоб переконатися, що questionвластивість має належний статус попередньо заповнена.
BalusC

@BalusC Як отримати порядкове значення з JSF?
коктейлі

2
Якщо ви, як і я, отримаєте виняток у форматі чисел += status, то спробуйте використовувати .concat(status)як пропонує @ Ziletka.
свист_мармот

Якщо ви віддаєте перевагу java.util.List, ви можете просто змінити тип повернення getStatuses () у Список <Status> та повернути Arrays.asList (Status.values ​​());
stakahop

16

Для локалізації ми можемо використовувати і це рішення:

public enum Status { SUBMITTED, REJECTED, APPROVED }

data.status.SUBMITTED=Submitted
data.status.REJECTED=Rejected
data.status.APPROVED=Approved

<h:selectOneMenu value="#{bean.question.status}" >
    <f:selectItems
        value="#{data.statuses}"
        var="status"
        itemValue="#{status}"
        itemLabel="#{text['data.status.'.concat(status)]}" />
</h:selectOneMenu>

Тому шлях ресурсу для рядків локалізації не кодується в Enum.


1
Зауважте, що цей синтаксис підтримується лише з EL 2.2, який є "відносно" новим. В іншому випадку ви завжди можете захопити <c:set>або <ui:param>або доморощений призначену для користувача функцію EL.
BalusC

Дякую, BalusC. Чи можна якось замінити # {data.statuses} класом enum, не використовуючи резервний бін (наприклад, значення = "# {org.myproject.Status.values}")?
sasynkamil

@BalusC ви впевнені? Я використовую GF 3.1.2 (Mojarra JSF 2.1.6).
sasynkamil

4

Ви можете використовувати <f:selectItems value="#{carBean.carList}" />та повертати список SelectItemекземплярів, які обертають перерахунок (використовувати Status.values()для отримання всіх можливих значень).


2

Ви можете використовувати наступну утиліту el для отримання значень enum та використовувати їх, SelectOneMenuнаприклад, у. Не потрібно створювати бобові та методи котлоагрегату.

public final class ElEnumUtils
{
    private ElEnumUtils() { }

    /**
     * Cached Enumerations, key equals full class name of an enum
     */
    private final static Map<String, Enum<?>[]> ENTITY_ENUMS = new HashMap<>();;

    /**
     * Retrieves all Enumerations of the given Enumeration defined by the
     * given class name.
     *
     * @param enumClassName Class name of the given Enum.
     *
     * @return
     *
     * @throws ClassNotFoundException
     */
    @SuppressWarnings("unchecked")
    public static Enum<?>[] getEnumValues(final String enumClassName) throws ClassNotFoundException
    {
        // check if already cached - use classname as key for performance reason
        if (ElEnumUtils.ENTITY_ENUMS.containsKey(enumClassName))
            return ElEnumUtils.ENTITY_ENUMS.get(enumClassName);

        final Class<Enum<?>> enumClass = (Class<Enum<?>>) Class.forName(enumClassName);

        final Enum<?>[] enumConstants = enumClass.getEnumConstants();

        // add to cache
        ElEnumUtils.ENTITY_ENUMS.put(enumClassName, enumConstants);

        return enumConstants;
    }
}

Зареєструйте його як функцію el у файлі taglib:

<function>
    <description>Retrieves all Enumerations of the given Enumeration defined by the given class name.</description>
    <function-name>getEnumValues</function-name>
    <function-class>
        package.ElEnumUtils
    </function-class>
    <function-signature>
        java.lang.Enum[] getEnumValues(java.lang.String)
    </function-signature>
</function>

І нарешті назвіть це так:

<p:selectOneMenu value="#{bean.type}">
    <f:selectItems value="#{el:getEnumValues('package.BeanType')}" var="varEnum" 
        itemLabel="#{el:getEnumLabel(varEnum)}" itemValue="#{varEnum}"/>
</p:selectOneMenu>

Відповідно до відповіді BalusC, ви повинні використовувати пакет ресурсів з локалізованими мітками перерахування, а для більш чистого коду ви також можете створити функцію, як getEnumLabel(enum)


Немає необхідності в "функції" (метод більше), коли ви можете використовувати, #{myBundle[enumName.i18nKey]}а потім вводити ключі i18n у ваше перерахування як властивості: BLA_TYPE("SOME_BLA_TYPE_KEY")by BLA_TYPE- це перелік, який слід використовувати, і SOME_BLA_TYPE_KEYце ключ i18n.
Роланд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.