2
votes

I set up a selectOneMenu with POJOs and a converter, in a p:dialog, see the sources below. It does work, except that initially, when it is first displayed in not-dropped-down state, the first choice is selected, not the one corresponding to the bean value. If I save the state of the selectOneMenu without interacting with it at all, the initially selected first choice is saved and so the real value is overwritten, but if I select a differenct choice, it is saved properly. The bean value to which the selectOneMenu is bound can't be null.

I debugged the converter, and it turned out, that when the backing data is loaded and the dialog is refreshed and displayed, all of the choices go through the converter's getAsString(), plus the choice for the real bean value again. Still, the first choice gets actually selected and displayed in the selectOneMenu. When the dialog's form is commited, the actually selected choice goes through the converter's getAsObject(), regardless whether that was the wrongly selected initial value or the manually selected one.

Please advise what might be the problem.

The xhtml of the button that invokes the dialog, this is in a different form:

<p:commandButton id="toolbarEditButton" 
            value="Edit selected" update=":editMediaForm"
            disabled="#{!contentManager.mediaSelected}"
            actionListener="#{contentManager.editSelectedMedia}"
            onclick="PF('editMediaWidget').show()" />

The xhtml of the dialog:

    <p:dialog id="editMediaDialog" widgetVar="editMediaWidget"
        modal="true" resizable="false" >
        <h:form id="editMediaForm" >
            <p:panelGrid rendered="#{contentManager.isMediaSelected()}" columns="2" >
                ... <!-- other properties of the selected element -->
                <p:outputLabel value="Media type" />
                <p:selectOneMenu value="#{contentManager.selectedMedia.mediaType}"
                                 converter="#{mediaTypeConverter}">
                    <f:selectItems value="#{mediaTypeConverter.allMediaTypes}"
                        var="mt" itemLabel="#{mt.name}" itemValue="#{mt}" />
                    <p:ajax listener="#{contentManager.onMediaTypeChanged()}" />
                </p:selectOneMenu>
            </p:panelGrid>
        </h:form>
    </p:dialog>

The converter:

@Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String stringId) {
    Long id = Long.valueOf(stringId);
    for (MediaType mt : mediaTypes) {
        if (mt.getPkid().equals(id)) {
            return mt;
        }
    }
    return null;
}

@Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object mtObj) {
    MediaType mt = (MediaType) mtObj;
    return mt.getPkid().toString();
}

public List<MediaType> getAllMediaTypes() {
    return mediaTypes;
}

Edit: the backing bean

@SessionScoped // javax.enterprise.context.SessionScoped
@Named("contentManager") // javax.inject.Named
public class ContentManager implements Serializable {
    ...
    private List<Media> mediaList;
    private Media selectedMedia = null;
    ...
    public boolean isMediaSelected() {
        if (selectedMedia == null) return false;
        return true;
    }
    ...
    public void saveSelectedMedia() {
        myDao.saveMedia(selectedMedia);
    }

    public void editSelectedMedia() {
        // only for debugging, could be removed
    }
}

The dialog is brought up and the form is updated by an edit button which is only available after an element is selected from a dataTable (selectedMedia). The update does seem to work, since the other properties of the selected element are properly updated and displayed in the dialog, so the bean value behind the selectOneMenu should be ok.

Update: of course I also examined the generated HTML. The <select> seems to be OK for me, it contains the proper values to be converted by the converter. (The selection is still wrong)

<select id="form:blah_input" name="form:blah_input" tabindex="-1">
    <option value="1" selected="selected">1 - half_horizontal</option>
    <option value="2">2 - half_vertical</option>
    <!-- etc -->
</select>
1
Is <p:dialog> inserted into another <h:form>? This might solve such inappropriate behaviourRafcik
please show the code and the scope of contentManager bean, the problem seem to be in thereNassim MOUALEK
Or try adding update="@form" to <p:ajax />. I am not sure if <p:ajax> should have attribute event="select OR change", but you can also check thisRafcik
Thank you for your comments. Answers in order of the comments: 1) different forms, not embedded into each other 2) please see the extended sources 3) the update happens on the edit event, not on the select, and as I mentioned, the update does work on the other properties of the same edited element in the same dialog.Alex Biro
I don't know if this is the issue here, but you should not use your converter to hold any values, in your case the list of mediaTypes. Rather create the search functionality in your service/controller class, inject it into the converter and call the method there. Something like in this answer stackoverflow.com/a/8001418/999488Emil Kaminski

1 Answers

4
votes

The objects displayed in the SelectOneMenu have to have proper equals() method, not only the default Object#equals which is only true if they are the same object. This explains why the initial displayed value was always the first: the bean value never matched any of the possible values, so the SelectOneMenu component simply displayed the first one.

So the mistake was not in the JSF or backing bean code, but in the displayed domain objects' (MediaType) code. Adding the equals() method there solved the problem.