0

I have a bean "Player" When I select a value in the selectOneMenu I would like to "switch" to the bean that's matching in the database.

I have the beans sent back to the select one menu in

public List<Player> getAllPlayers() { }

Updated the dropdown to this.

<h:selectOneMenu value="#{servicePlayer.myPlayer.combinedName}"
    converter="playerConverter" id="playerList">
    <f:selectItems value="#{servicePlayer.allPlayers}" var="player"
        itemLabel="#{player.combinedName}" itemValue="#{player.id}" />
</h:selectOneMenu>

But I still can't get it to send the ID to the converter. It will send in the firstName from the player.

@FacesConverter(value = "playerConverter")
public class PlayerConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if (value == null) {
            return null;
        }

        long idValue;
        try {
            idValue = Long.parseLong(value);
        }
        catch (NumberFormatException ex)
        {
            return null;
        }

        ServicePlayer servicePlayer = context.getApplication()
                .evaluateExpressionGet(context, "#{servicePlayer}",
                        ServicePlayer.class);
        Player player = servicePlayer.getPlayerByID(idValue);
        return player;

    }

    @Override
    public String getAsString(FacesContext arg0, UIComponent arg1, Object value) {
        String string = null;
        if (value instanceof Player) {
            string = ((Player) value).getFirstName();
        }
        return string;
    }

}

public class ServicePlayer {

    private static final String PERSISTENCE_UNIT_NAME = "BowlingFacelets";
    public static EntityManagerFactory factory;
    Player myPlayer;

    public Player getMyPlayer() {
        return myPlayer;
    }


    public void setMyPlayer(Player myPlayer) {
        this.myPlayer = myPlayer;
    }


    public List<Player> getAllPlayers() {

        if (factory == null) {
            factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
        }

        EntityManager em = factory.createEntityManager();
        //Order by the matchdate.
        //Query q = em.createQuery("select t from DBTest t");
        Query q = em.createQuery("select t from Player t");

        List<Player> players = q.getResultList();
        for (Player aPlayer : players) {
          System.out.println(aPlayer);
        }
        System.out.println("Size: " + players.size());

        em.close();

        return players;
    }


public Player getPlayerByID(long id) {

        if (factory == null) {
            factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
        }

        EntityManager em = factory.createEntityManager();
        //Query q = em.createQuery("select t from Player t where t.name = '" + playerName + "'");
        //List<Player> players = q.getResultList();
        Player currentPlayer = em.find(Player.class, id);

        return currentPlayer;

    }


}
Aritz
  • 30,971
  • 16
  • 136
  • 217
user2130951
  • 2,601
  • 4
  • 31
  • 58

2 Answers2

1

I think you've misunderstood what the value attribute of the selectOneMenu refers to. It's use is like in all other input components the place to store the user input (or where to take an existing value from).

Check http://www.jsftoolbox.com/documentation/help/12-TagReference/core/f_selectItems.html. You will need to set key and value pairs based on a 'var' attribute on the f:select items, else JSF has no real way of knowing what you want to do with the Player object.

So given that key/value pairs (key goes into whatever you sets as the value attribute and value is shown to the user) is in place, and if you for example use the player.id as the value, you can fetch a user based on that id.

Luc
  • 273
  • 1
  • 9
  • I can't use the ID as I am trying here. Since that would not be human readable. How would you suggest that I get the ID in this case from player.firstName (shown in the selectonemenu). There is no way to guarantee that there is only one instance of a name in the database. – user2130951 Dec 17 '13 at 12:31
  • You can use the id as the value of the option and set the label to for example firstName. Again, the label is what is shown to the user and the value what you use in your logic. – Luc Dec 17 '13 at 12:35
  • Still can't get it to work. Added converter and new JSF code. – user2130951 Dec 17 '13 at 13:53
  • Try skipping the converter and instead introduce a 'String selectedPlayerId' to the ServicePlayer bean and use that as the 'value' of the selectOneMenu. Then, when displaying the selected player, base that on the id now present in 'selectedPlayerID' and use your getPlayerById. – Luc Dec 17 '13 at 14:23
0

A JSF Converter does the job of converting an Object to the string value for the itemValue attribute and then recover that Object from the string value. For your case, the Object is the Player entity while the value is the String representation of its id (could be anything else, as long as you know it's unique).

Basically, using this converter:

@FacesConverter(value = "playerConverter")
public class PlayerConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if (value == null) {
            return null;
        }

        long idValue;
        try {
            idValue = Long.parseLong(value);
        }
        catch (NumberFormatException ex)
        {
            return null;
        }

        ServicePlayer servicePlayer = context.getApplication()
                .evaluateExpressionGet(context, "#{servicePlayer}",
                        ServicePlayer.class);
        Player player = servicePlayer.getPlayerByID(idValue);
        return player;

    }

    @Override
    public String getAsString(FacesContext arg0, UIComponent arg1, Object value) {
        String string = null;
        if (value instanceof Player) {
            string = ((Player) value).getId();
        }
        return string;
    }

}

Note I changed the name you're returning by the id. That way, being the player id 1, JSF knows the String value for that is "1". That's the value for the selection, which is obtained by the getAsString method.

When you POST the form, JSF has to recover the Player entity from the "1" value, so you use Converter's getAsObject to load it from the DB.

That way it would be enough to reference the object itself from the view to let jsf do the conversion:

<h:selectOneMenu value="#{servicePlayer.myPlayer.combinedName}"
    converter="playerConverter" id="playerList">
    <f:selectItems value="#{servicePlayer.allPlayers}" var="player"
        itemLabel="#{player.combinedName}" itemValue="#{player}" />
</h:selectOneMenu>
Aritz
  • 30,971
  • 16
  • 136
  • 217
  • See http://stackoverflow.com/questions/20652484/wrong-value-being-sent-to-converter-jsf for the complete solution – user2130951 Dec 18 '13 at 10:26
  • For next time, please don't post questions twice. One of SO aims is to be kind of repository of common knowledge, duplicating things makes it worse. – Aritz Dec 18 '13 at 10:28
  • Well actually this question didn't solve it for me. The other did. So for me it definitely got it better. – user2130951 Dec 18 '13 at 10:39
  • I mean, it's better to maintain only one post for the thread. If you want, you can edit it and add new content/tested cases, this will keep the post with the trended ones. Just don't press "Ask Question" again. – Aritz Dec 18 '13 at 10:45