Come usare i valori enum in f: selectItem (s)


103

Desidero creare un menu a discesa selectOneMenu in modo da poter selezionare uno stato sulla mia domanda. È possibile rendere f: selectItem più flessibile considerando cosa succede se l'ordine delle enumerazioni cambia e se l'elenco era grande? E potrei farlo meglio? Ed è possibile "selezionare" automaticamente l'elemento che contiene la domanda?

Classe Enum

public enum Status {
    SUBMITTED,
    REJECTED,
    APPROVED
}

Entità della domanda

@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>

Risposte:


210

JSF ha un convertitore integrato per enum, quindi questo dovrebbe fare:

@ManagedBean
@ApplicationScoped
public class Data {

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

}

con

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

(nota: poiché JSF 2.0 non è più necessario fornire un SelectItem[]or List<SelectItem>, a T[]e List<T>sono accettati anche e puoi accedere all'elemento corrente per varattributo)

Se ti capita di utilizzare la libreria di utilità JSF OmniFaces , puoi utilizzare al <o:importConstants>posto di un bean.

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

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

Se intendi controllare anche le etichette, puoi aggiungerle Statusall'enumerazione:

public enum Status {

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

    private String label;

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

    public String getLabel() {
        return label;
    }

}

con

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

O, meglio, rendi il valore enum una chiave di proprietà di un bundle di risorse localizzato (EL 3.0 richiesto):

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

con questo in un file delle proprietà associato al bundle di risorse #{text}

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

Una cosa BalusC, è che è possibile "selezionare" / visualizzare lo stato che una domanda ha come predefinito (per esempio quando stai modificando una domanda, hai già impostato lo stato della domanda su qualcosa)
LuckyLuke

Nell'esempio precedente, JSF lo farà per impostazione predefinita quando #{bean.question.status}ha un valore enum valido. Non è necessario fare nulla per assicurarsi che la questionproprietà di stato corretta sia precompilata.
BalusC

@BalusC Come accedere al valore ordinale da JSF?
jacktrades

2
Se, come me, ottieni un'eccezione per il formato numerico += status, prova a utilizzare .concat(status)come suggerisce @Ziletka.
whistling_marmot

Se preferisci java.util.List puoi semplicemente modificare il tipo di ritorno getStatuses () in List <Status> e restituire Arrays.asList (Status.values ​​());
stakahop

16

Per la localizzazione possiamo utilizzare anche questa soluzione:

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>

Quindi il percorso della risorsa per le stringhe di localizzazione non è codificato in Enum.


1
Notare che questa sintassi è supportata solo a partire da EL 2.2, che è "relativamente" nuovo. Altrimenti puoi sempre prendere <c:set>o creare in <ui:param>casa una funzione EL personalizzata.
BalusC

Grazie BalusC. È possibile in qualche modo sostituire # {data.statuses} con enum Class, senza utilizzare il backing bean (es. Value = "# {org.myproject.Status.values}")?
sasynkamil

@BalusC sei sicuro? Sto usando GF 3.1.2 (Mojarra JSF 2.1.6).
sasynkamil

4

È possibile utilizzare <f:selectItems value="#{carBean.carList}" />e restituire un elenco di SelectItemistanze che racchiudono l'enumerazione (utilizzare Status.values()per ottenere tutti i valori possibili).


2

È possibile utilizzare la seguente funzione di utilità el per ottenere i valori enum e utilizzarli SelectOneMenuad esempio in a. Non c'è bisogno di creare fagioli e metodi boilerplate.

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;
    }
}

Registralo come funzione el in un file 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>

E infine chiamalo come:

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

Simile alla risposta BalusC dovresti usare un bundle di risorse con etichette enum localizzate e per un codice più pulito puoi anche creare una funzione come getEnumLabel(enum)


Non c'è bisogno di una "funzione" (metodo more), quando puoi usare #{myBundle[enumName.i18nKey]}e poi mettere le chiavi i18n nella tua enumerazione come proprietà: BLA_TYPE("SOME_BLA_TYPE_KEY")by BLA_TYPEè l'enum da usare ed SOME_BLA_TYPE_KEYè la chiave i18n.
Roland
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.