Why selectOneMenu Send ItemLabel to the converter?

前端 未结 4 2055
孤独总比滥情好
孤独总比滥情好 2020-12-01 17:20

my JSF page



                      
     

        
相关标签:
4条回答
  • 2020-12-01 17:33

    You have to use selectitem list in the f:selecitems attribute of h:selectOneMenu

    Your page will be like this;

    <h:form>   
      <h:selectOneMenu id="studlist" value="#{studBean.selectedStudent}">
         <p:ajax event="change" process="studlist" update="studdep" ></p:ajax>     
         <f:selectItems value="#{studBean.studentSelectItemList}" />     
       <f:converter   converterId="studentconverter"/>     
      </h:selectOneMenu>
    </h:form>
    

    At the backing bean side you have to fill the studentSelectItemList selectitem.

    private List<SelectItem> studentSelectItemList;
    
    //fill studentSelectItemList at the appropriate place
      studentSelectItemList.add(new SelectItem(studentId,studentName));
    

    After these settings you should have student id as select value.

    0 讨论(0)
  • 2020-12-01 17:34

    Today I had the same problem.

    It is caused by this wrong rendering:

    <select ...>
        <option>None</option>
        <option value="1">First</option>
        <option value="2">Second</option>
    </select>
    

    omitting value="" for "None" option result in submitting the label instead of an empty string.

    However to solve this and make the renderer write value="" for the first option just make sure getAsString() never returns null, return "" (empty string) instead.


    @BalusC

    <h:form id="form">
        ...
    
        <p:selectOneMenu id="targetStep" value="#{action.targetStep}" required="true">
            <o:converter converterId="omnifaces.ListIndexConverter" list="#{entity.stepList}" />
            <f:selectItems var="step" value="#{entity.stepList}" itemLabel="#{step.name}" 
                itemValue="#{step}" />
        </p:selectOneMenu>
    
        <p:commandButton process="@this" update="@widgetVar(stepDialog)" 
            oncomplete="PF('stepDialog').show()" icon="#{icons.addStep}" 
            value="#{bundle.addStep}">
            <f:setPropertyActionListener target="#{viewScope.step}"
                value="#{s:newInstance('it.shape.edea2.jpa.WorkflowStep')}" />
        </p:commandButton>
    
        <p:message for="targetStep" />
    
        ...
    </h:form>
    
    <p:dialog widgetVar="stepDialog" header="#{bundle.addStep}" modal="true" dynamic="true"
        resizable="false">
        <h:form>
            <p:panelGrid columns="2" styleClass="app-full-width">
                <h:outputLabel value="#{bundle.name}" />
                <h:panelGroup>
                    <p:inputText id="name" value="#{step.name}" required="true" />
                    <p:message for="name" />
                </h:panelGroup>
    
                ...
    
                <f:facet name="footer">
                    <p:commandButton process="@form" update="@form :form"
                        oncomplete="hideDialog('stepDialog', args)" icon="#{icons.confirm}"
                        value="#{bundle.confirm}">
                        <p:collector value="#{step}" addTo="#{entity.stepList}" />
                        <f:setPropertyActionListener target="#{action.targetStep}"
                            value="#{step}" />
                    </p:commandButton>
                </f:facet>
            </p:panelGrid>
        </h:form>
    </p:dialog>
    

    Your omnifaces.ListIndexConverter to the rescue :)

    0 讨论(0)
  • 2020-12-01 17:46

    I'm not sure why you got the item label instead of the item value inside getAsObject(). Perhaps your getAsString() is doing it wrong and it is returning student name based on the student ID.

    At any way, I can tell that your itemValue is definitely not right.

    <h:selectOneMenu id="studlist" value="#{studBean.selectedStudent}">  
        <f:selectItems value="#{studBean.student}" var="s" 
            itemValue="#{s.studid}" itemLabel="#{s.name}" />
        <f:converter converterId="studentconverter" />
    </h:selectOneMenu>
    

    A converter is intented to be used to convert between a complex Java object and a String representation so that it can be passed around as a HTTP request parameter. However, you're specifying the student ID as item value instead of the whole student object. You need to specify the whole student object instead. You should also ensure that #{studBean.selectedStudent} refers to a Student property, not some Long property representing the student ID.

    When you fix the itemValue as follows:

    <h:selectOneMenu id="studlist" value="#{studBean.selectedStudent}">  
        <f:selectItems value="#{studBean.student}" var="s" 
            itemValue="#{s}" itemLabel="#{s.name}" />
        <f:converter converterId="studentconverter" />
    </h:selectOneMenu>
    

    and your converter as follows (trivial nullchecks omitted):

    public String getAsString(FacesContext context, UIComponent component, Object value) {
        // This method is called when item value is to be converted to HTTP request parameter.
        // Normal practice is to return an unique identifier here, such as student ID.
        Student student = (Student) value;
        Long id = student.getStudid();
        return String.valueOf(id);
    }
    
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        // This method is called when HTTP request parameter is to be converted to item value.
        // You need to convert the student ID back to Student.
        Long id = Long.valueOf(value);
        Student student = someStudentService.find(id);
        return student;
    }
    

    then it ought to work.

    Alternatively, you could keep your itemValue as you initially had and remove the <f:converter> altogether, but then you have to change #{studBean.selectedStudent} to point to a Long property representing the student ID.

    0 讨论(0)
  • 2020-12-01 17:51

    BalusC (again) nailed this one for me. I had the same problem and as BalusC pointed out earlier my converter's getAsString() method returned my object's "firstname" property.

    @Override public String getAsString(FacesContext context, UIComponent component, Object value) {

        if (value == null || value.equals("")) {
            return "";
        }
        else {
            return String.valueOf(((Employee) value).getfirstname());
        }
    
    }
    

    I changed this to return the id and it started working as expected.

    @Override public String getAsString(FacesContext context, UIComponent component, Object value) {

        if (value == null || value.equals("")) {
            return "";
        }
        else {
            return String.valueOf(((Employee) value).getId());
        }
    
    }
    

    BalusC your effort to explain the theory is hugely appreciated. You're heavensent!

    0 讨论(0)
提交回复
热议问题