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.