2

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>
Alex Biro
  • 1,069
  • 1
  • 14
  • 27
  • Is `` inserted into another ``? This might solve such inappropriate behaviour – Rafcik Jul 30 '15 at 09:05
  • please show the code and the scope of contentManager bean, the problem seem to be in there – Nassim MOUALEK Jul 30 '15 at 09:07
  • Or try adding `update="@form"` to ``. I am not sure if `` should have attribute `event="select OR change"`, but you can also check this – Rafcik Jul 30 '15 at 09:11
  • 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 Jul 30 '15 at 10:50
  • 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 http://stackoverflow.com/a/8001418/999488 – Emil Kaminski Jul 30 '15 at 11:17
  • I don't think either that this is the problem here, and also, this is a different usecase. The items the converter converts (MediaTypes in particular here) are rarely changed, when a new one is inserted, probably other changes are made to the application too and it might even be redeployed. So the converter is applicationScoped, and the list is populated in the `@PostConstruct` method. This way the controller is kind of a cache. If needed, it still can be extended with periodical or triggerable refresh. – Alex Biro Jul 30 '15 at 11:42

1 Answers1

5

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.

Alex Biro
  • 1,069
  • 1
  • 14
  • 27