Comment remplir les options de h: selectOneMenu from database?

Je crée une application Web, où vous devez lire une liste d’objects / entités à partir d’une firebase database et la remplir dans un JSF . Je suis incapable de coder ceci. Est-ce que quelqu’un peut me montrer comment le faire?

Je sais comment obtenir une List de la firebase database. Ce que je dois savoir, c’est comment remplir cette liste dans un .

  ...?  

    D’après l’historique de vos questions, vous utilisez JSF 2.x. Donc, voici une réponse ciblée JSF 2.x. Dans JSF 1.x, vous seriez obligé d’emballer des valeurs / étiquettes d’éléments dans des instances SelectItem laides. Ce n’est heureusement plus nécessaire dans JSF 2.x.


    Exemple de base

    Pour répondre directement à votre question, utilisez simplement dont la value pointe sur une propriété List que vous conservez dans la firebase database pendant la construction (post) du bean. Voici un exemple de démarrage de base supposant que T représente réellement une Ssortingng .

        

    avec

     @ManagedBean @RequestScoped public class Bean { private Ssortingng name; private List names; @EJB private NameService nameService; @PostConstruct public void init() { names = nameService.list(); } // ... (getters, setters, etc) } 

    Aussi simple que cela. En fait, le toSsortingng() du T sera utilisé pour représenter à la fois le libellé et la valeur de l’élément déroulant. Donc, quand vous êtes à la place de List utilisant une liste d’objects complexes comme List et que vous n’avez pas remplacé la toSsortingng() la classe ‘ toSsortingng() , alors vous List comme élément valeurs. Voir la section suivante comment la résoudre correctement.

    Notez également que le bean pour la valeur ne doit pas nécessairement être le même bean que le bean pour la valeur . Ceci est utile lorsque les valeurs sont en réalité des constantes à l’échelle de l’application que vous devez simplement charger une seule fois au démarrage de l’application. Vous pourriez alors en faire une propriété d’un bean de scope d’application.

        

    Objets complexes comme éléments disponibles

    Chaque fois que T concerne un object complexe (un javabean), tel que User qui possède une propriété Ssortingng de name , vous pouvez utiliser l’atsortingbut var pour obtenir la variable d’itération que vous pouvez utiliser à son tour dans les itemValue et / ou itemLabel ( Si vous omettez l’ itemLabel , l’étiquette devient la même que la valeur).

    Exemple 1:

        

    avec

     private Ssortingng userName; private List users; @EJB private UserService userService; @PostConstruct public void init() { users = userService.list(); } // ... (getters, setters, etc) 

    Ou lorsqu’il a un id propriété Long que vous souhaitez définir comme valeur d’élément:

    Exemple # 2:

        

    avec

     private Long userId; private List users; // ... (the same as in previous bean example) 

    Objet complexe en tant qu’élément sélectionné

    Chaque fois que vous souhaitez également définir une propriété T dans le bean et que T représente un User , vous devez alors créer un Converter personnalisé qui convertit l’ User une représentation de chaîne unique (qui peut être la propriété id ). Notez que la valeur itemValue doit représenter l’object complexe lui-même, exactement le type qui doit être défini en tant que value du composant de sélection.

        

    avec

     private User user; private List users; // ... (the same as in previous bean example) 

    et

     @ManagedBean @RequestScoped public class UserConverter implements Converter { @EJB private UserService userService; @Override public Object getAsObject(FacesContext context, UIComponent component, Ssortingng submittedValue) { if (submittedValue == null || submittedValue.isEmpty()) { return null; } try { return userService.find(Long.valueOf(submittedValue)); } catch (NumberFormatException e) { throw new ConverterException(new FacesMessage(Ssortingng.format("%s is not a valid User ID", submittedValue)), e); } } @Override public Ssortingng getAsSsortingng(FacesContext context, UIComponent component, Object modelValue) { if (modelValue == null) { return ""; } if (modelValue instanceof User) { return Ssortingng.valueOf(((User) modelValue).getId()); } else { throw new ConverterException(new FacesMessage(Ssortingng.format("%s is not a valid User", modelValue)), e); } } } 

    (notez que le Converter est un peu piraté pour pouvoir injecter un @EJB dans un convertisseur JSF; normalement, il aurait été annoté comme @FacesConverter(forClass=User.class) , mais cela ne permet malheureusement pas @EJB Injections d’ @EJB )

    N’oubliez pas de vous assurer que equals() et hashCode() correctement implémentés dans la classe d’object complexe. Dans le cas contraire, JSF ne pourra pas afficher les éléments présélectionnés et l’ erreur de validation se produira sur la page d’envoi. valide

     public class User { private Long id; @Override public boolean equals(Object other) { return (other != null && getClass() == other.getClass() && id != null) ? id.equals(((User) other).id) : (other == this); } @Override public int hashCode() { return (id != null) ? (getClass().hashCode() + id.hashCode()) : super.hashCode(); } } 

    Objets complexes avec un convertisseur générique

    Dirigez-vous vers cette réponse: Implémentez des convertisseurs pour les entités avec Java Generics .


    Objets complexes sans convertisseur personnalisé

    La bibliothèque d’utilitaires JSF OmniFaces propose un convertisseur spécial qui vous permet d’utiliser des objects complexes dans sans avoir besoin de créer un convertisseur personnalisé. SelectItemsConverter effectuera simplement la conversion en fonction des éléments facilement disponibles dans .

        

    Voir également:

    • Notre page wiki

    Voir page

        

    Haricot

      List names = new ArrayList(); //-- Populate list from database names.add(new SelectItem(valueObject,"label")); //-- setter/getter accessor methods for list 

    Pour afficher un enregistrement sélectionné particulier, il doit s’agir d’une des valeurs de la liste.

    Convertisseur générique pour objects complexes en tant qu’élément sélectionné

    Le Balusc donne une réponse très utile à ce sujet. Mais il n’y a pas une alternative qu’il propose: le convertisseur générique Roll-your-own qui gère les objects complexes en tant qu’élément sélectionné. C’est très complexe à faire si vous voulez gérer tous les cas, mais assez simple pour les cas simples.

    Le code ci-dessous contient un exemple d’un tel convertisseur. Il fonctionne dans le même esprit que le SelectItemsConverter d’ OmniFaces car il examine les enfants d’un composant pour UISelectItem(s) contenant des objects. La différence est qu’elle ne gère que les liaisons vers des collections simples d’objects d’entité ou vers des chaînes. Il ne gère pas les groupes d’éléments, les collections de SelectItem , les tableaux et probablement beaucoup d’autres choses.

    Les entités auxquelles le composant se lie doivent implémenter l’interface IdObject . (Cela pourrait être résolu autrement, comme l’utilisation de toSsortingng .)

    Notez que les entités doivent implémenter des équivalents de manière à ce que deux entités avec le même ID soient égales.

    La seule chose à faire pour l’utiliser est de le spécifier en tant que convertisseur sur le composant select, de lier à une propriété d’entité et une liste d’entités possibles:

          

    Convertisseur:

     /** * A converter for select components (those that have select items as children). * * It convertes the selected value ssortingng into one of its element entities, thus allowing * binding to complex objects. * * It only handles simple uses of select components, in which the value is a simple list of * entities. No ItemGroups, arrays or other kinds of values. * * Items it binds to can be ssortingngs or implementations of the {@link IdObject} interface. */ @FacesConverter("selectListConverter") public class SelectListConverter implements Converter { public static interface IdObject { public Ssortingng getDisplayId(); } @Override public Object getAsObject(FacesContext context, UIComponent component, Ssortingng value) { if (value == null || value.isEmpty()) { return null; } return component.getChildren().stream() .flatMap(child -> getEnsortingesOfItem(child)) .filter(o -> value.equals(o instanceof IdObject ? ((IdObject) o).getDisplayId() : o)) .findAny().orElse(null); } /** * Gets the values stored in a {@link UISelectItem} or a {@link UISelectItems}. * For other components returns an empty stream. */ private Stream getEnsortingesOfItem(UIComponent child) { if (child instanceof UISelectItem) { UISelectItem item = (UISelectItem) child; if (!item.isNoSelectionOption()) { return Stream.of(item.getValue()); } } else if (child instanceof UISelectItems) { Object value = ((UISelectItems) child).getValue(); if (value instanceof Collection) { return ((Collection) value).stream(); } else { throw new IllegalStateException("Unsupported value of UISelectItems: " + value); } } return Stream.empty(); } @Override public Ssortingng getAsSsortingng(FacesContext context, UIComponent component, Object value) { if (value == null) return null; if (value instanceof Ssortingng) return (Ssortingng) value; if (value instanceof IdObject) return ((IdObject) value).getDisplayId(); throw new IllegalArgumentException("Unexpected value type"); } } 

    Je le fais comme ça:

    1. Les modèles sont ViewScoped

    2. convertisseur:

       @Named @ViewScoped public class ViewScopedFacesConverter implements Converter, Serializable { private static final long serialVersionUID = 1L; private Map converterMap; @PostConstruct void postConstruct(){ converterMap = new HashMap<>(); } @Override public String getAsString(FacesContext context, UIComponent component, Object object) { String selectItemValue = String.valueOf( object.hashCode() ); converterMap.put( selectItemValue, object ); return selectItemValue; } @Override public Object getAsObject(FacesContext context, UIComponent component, String selectItemValue){ return converterMap.get(selectItemValue); } } 

    et lier au composant avec:

       

    Si vous utilisez un identifiant d’entité plutôt qu’un hashCode, vous pouvez bash une collision si vous avez peu de listes sur une page pour différentes entités (classes) avec le même identifiant.

    Appelez-moi paresseux, mais coder un convertisseur semble être un travail inutile. J’utilise les Primefaces et, n’ayant pas déjà utilisé une liste déroulante JSF2 ou un menu déroulant simple, j’ai simplement supposé (paresseux) que le widget pouvait gérer des objects complexes, c.-à-d. beaucoup d’autres widgets font. J’ai été déçu de constater (après des heures de grattage) que cette capacité n’existe pas pour ce type de widget sans convertisseur. En fait, si vous fournissez un setter pour l’object complexe plutôt que pour une chaîne, il échoue silencieusement (il n’appelle pas simplement le setter, pas d’exception, pas d’erreur JS) et j’ai passé beaucoup de temps avec l’excellent outil de dépannage de BalusC pour trouver la cause, en vain puisque aucune de ces suggestions appliquées. Ma conclusion: le widget listbox / menu doit être adapté aux autres widgets JSF2. Cela semble trompeur et enclin à conduire le développeur non informé comme moi dans un trou de lapin.

    En fin de compte, j’ai résisté au codage d’un convertisseur et j’ai trouvé par essais et erreurs que si vous définissiez la valeur du widget sur un object complexe, par exemple:

      

    … lorsque l’utilisateur sélectionne un élément, le widget peut appeler un object Ssortingng setter pour cet object, par exemple setSelectedThing(Ssortingng thingSsortingng) {...} et la chaîne transmise est une chaîne JSON représentant l’object Thing. Je peux l’parsingr pour déterminer quel object a été sélectionné. Cela ressemble un peu à un piratage, mais moins à un piratage qu’un convertisseur.