web-dev-qa-db-fra.com

Comment utiliser les valeurs enum dans f: selectItem (s)

Je souhaite créer un menu déroulant selectOneMenu afin de pouvoir sélectionner un statut pour ma question. Est-il possible de rendre le f: selectItem plus flexible en considérant ce qui se passe si l'ordre des enums change, et si la liste était longue? Et pourrais-je faire cela mieux? Et est-il possible de "sélectionner" automatiquement l'élément que la question contient?

Enum class

public enum Status {
    SUBMITTED,
    REJECTED,
    APPROVED
}

entité Question

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

JSF a un convertisseur intégré pour enum, cela devrait donc:

@ManagedBean
@ApplicationScoped
public class Data {

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

}

avec

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

(remarque: depuis JSF 2.0, il n'est plus nécessaire de fournir un SelectItem[] ou List<SelectItem>, une T[] et List<T> sont également acceptés et vous pouvez accéder à l’élément en cours avec var attribut)

Si vous utilisez la bibliothèque d’utilitaires JSF OmniFaces , vous pouvez utiliser <o:importConstants> au lieu d'un haricot.

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

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

Si vous avez également l'intention de contrôler les étiquettes, vous pouvez les ajouter à l'énumération 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;
    }

}

avec

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

Ou mieux, faites de la valeur enum une clé de propriété d'un regroupement de ressources localisées (EL 3.0 requise):

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

avec cela dans un fichier de propriétés associé au groupe de ressources #{text}

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

Pour la localisation, nous pouvons également utiliser cette solution:

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>

Ainsi, le chemin d'accès aux ressources pour les chaînes de localisation n'est pas codé en dur dans Enum.

16
Ziletka

Vous pouvez utiliser <f:selectItems value="#{carBean.carList}" /> Et renvoyer une liste d'instances SelectItem qui encapsulent l'énumération (utilisez Status.values() pour obtenir toutes les valeurs possibles).

4
Thomas

Vous pouvez utiliser l'utilitaire el suivant pour obtenir les valeurs enum et les utiliser dans un SelectOneMenu par exemple. Pas besoin de créer des haricots et des méthodes passe-partout.

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

Enregistrez-le en tant que fonction el dans un fichier 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>

Et enfin, appelez ça comme:

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

Comme pour la réponse BalusC, vous devriez utiliser un ensemble de ressources avec des étiquettes d'énum localisées. Pour un code plus propre, vous pouvez également créer une fonction comme getEnumLabel(enum)

2
djmj