110 votes

Comment utiliser les valeurs d'un enum dans f:selectItem(s) ?

Je veux créer un menu déroulant selectOneMenu pour pouvoir sélectionner un état sur 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 est grande ? Et pourrais-je faire cela mieux ? Et est-il possible de "sélectionner" automatiquement l'élément que la question a ?

Classe Enum

public enum Status {
    SUBMITTED,
    REJECTED,
    APPROVED
}

Entité chargée des questions

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

224voto

BalusC Points 498232

JSF dispose d'un convertisseur intégré de enum donc cela devrait suffire :

@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 fichier de type SelectItem[] ou List<SelectItem> , a T[] et List<T> sont également acceptées et vous pouvez accéder à l'élément en cours par var attribut)

Si vous utilisez la bibliothèque d'utilitaires JSF OmniFaces alors 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 l'intention de contrôler également les étiquettes, vous pouvez les ajouter à l'option Status enum :

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 encore, faire de la valeur de l'enum une clé de propriété d'un ensemble de ressources localisées (EL 3.0 requis) :

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

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

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

0 votes

Une chose BalusC, est-il possible de "sélectionner"/voir le statut qu'une question a par défaut (par exemple lorsque vous éditez une question alors vous avez déjà défini le statut de la question à quelque chose)

0 votes

Dans l'exemple ci-dessus, JSF le fera par défaut lorsque #{bean.question.status} a une valeur d'enum valide. Vous n'avez pas besoin de faire quoi que ce soit à part vous assurer que l'enum est valide. question a la propriété d'état appropriée pré-remplie.

0 votes

@BalusC Comment accéder à une valeur ordinale depuis JSF ?

17voto

Ziletka Points 190

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 des ressources pour les chaînes de localisation n'est pas codé en dur dans l'Enum.

1 votes

Notez que cette syntaxe n'est prise en charge que depuis EL 2.2, qui est "relativement" récente. Sinon, vous pouvez toujours utiliser <c:set> o <ui:param> ou créer une fonction EL personnalisée.

0 votes

Merci BalusC. Est-il possible de remplacer #{data.statuses} par enum Class, sans utiliser de backing bean (par exemple value="#{org.myproject.Status.values}") ?

0 votes

@BalusC vous êtes sûr ? J'utilise GF 3.1.2 (Mojarra JSF 2.1.6).

4voto

Thomas Points 35713

Vous pourriez utiliser <f:selectItems value="#{carBean.carList}" /> et retourner une liste de SelectItem qui englobent l'enum (utilisez Status.values() pour obtenir toutes les valeurs possibles).

2voto

djmj Points 2251

Vous pouvez utiliser la fonction utilitaire el suivante pour obtenir les valeurs de l'enum et les utiliser dans un fichier de type SelectOneMenu par exemple. Il n'est pas nécessaire de créer des beans 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-la comme une 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 l'appeler comme ça :

<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 de BalusC, vous devriez utiliser un paquet de ressources avec des étiquettes d'énumération localisées et pour un code plus propre, vous pouvez également créer une fonction telle que getEnumLabel(enum)

0 votes

Pas besoin d'une "fonction" (méthode plus), quand on peut utiliser #{myBundle[enumName.i18nKey]} et ensuite mettre les clés i18n dans votre énumération comme propriétés : BLA_TYPE("SOME_BLA_TYPE_KEY") par BLA_TYPE est l'enum à utiliser et SOME_BLA_TYPE_KEY est la clé i18n.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X