TheCoder4eu / BootsFaces-OSP

BootsFaces - Open Source Project
Apache License 2.0
246 stars 102 forks source link

b:selectOneMenu doesn't recognize value from SelectItems collection with disabled attribute set to true. #907

Closed modima65 closed 6 years ago

modima65 commented 6 years ago

No error, silent.

b:selectOneMenu value and SelectItems collection are prepared and set in the same bean prior to render page. One of the values in the collection matches exactly the value in b:selectOneMenu. When b:selectOneMenu disabled attribute is false or not specified (default), the value in such component matches correctly the one in the f:selectItems collection. When b:selectOneMenu disabled attribute is true, the value in such component does not match the value in the f:selectItems collection and the component shows empty value.

When BootsFaces b:selectOneMenu is replaced by JSF h:selectOneMenu the value matches the one in the f:selectItems collection whether disabled attribute be set to true or false.

The Bean:

@Named(value = "fletesController")
@ViewScoped
public class FletesController implements Serializable{
    private Flete selectedFlete; // Row selected from b:dataTable with onEdit listener
    private List<SelectItem> tipos;    
    private FleteDaoImpl dao;

    @PostConstruct
    private void initController() {
        tipos = new ArrayList<>();
        tipos.add(new SelectItem("01", "Wood"));
        tipos.add(new SelectItem("02", "Steel"));
        tipos.add(new SelectItem("03", "Plastic"));
        dao = new FleteDaoImpl();
    }

     // Listener in b:dataTable commandButton
    public onEdit(Flete flete) {
        selectedFlete = dao.findById(Flete.class, flete.id);
        System.out.println("The value TIPO comes from database: " + selectedFlete.getTipo());
    }

        // Getters and Setters
}

The XHTML:

<h:form>
...
<b:dataTableColumn label="Consultar" searchable="false" orderable="false" headerStyle="text-align: center;" contentStyle="text-align: center;">
     <b:commandButton look="info" icon="eye-open" ajax="true" process="@this" actionListener="#{fletesController.onEdit(flete)}" update="@(.modalFleEdit)" oncomplete="$('.modalFleEdit').modal('show')">
          <f:param name="disabledToggle" value="true" transient="true"/>
     </b:commandButton>
</b:dataTableColumn>
...
<b:modal title="Flete Id: #{fletesController.selectedFlete.id}" class="modalFleEdit" closable="false">
     <b:panelGrid id="panelFleEdit" columns="2">
          <b:selectOneMenu value="#{fletesController.selectedFlete.tipo}" label-col-md="8" label="Tipo:" disabled="#{param['disabledToggle']}">
           <f:selectItems value="#{fletesController.tipos}"/>
          </b:selectOneMenu>
...
     </b:panelGrid>
</b:modal>
...
</h:form>

I have to use two components: one h:outputText for disabled situation and one b:selectOneMenu when enabled, but toggling rendered.

stephanrauh commented 6 years ago

Thanks for your detailed bug description! That should help us to find and solve the bug quickly.

stephanrauh commented 6 years ago

Did I simplify your example too much? My version works like charm. Can you have a look at it, please? Maybe it helps to track down the bug.

BTW, you can also inspect the result of the AJAX response after clicking the button. Maybe there's a difference between the disabled and the regular case?

Here`s my bean:

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.model.SelectItem;

@ManagedBean
@ViewScoped
public class FletesController implements Serializable {
    private static final long serialVersionUID = 1L;

    private List<SelectItem> tipos;

    private SelectItem selectedFlete = new SelectItem("02", "Steel");

    public FletesController() {
        tipos = new ArrayList<>();
        getTipos().add(new SelectItem("01", "Wood"));
        getTipos().add(new SelectItem("02", "Steel"));
        getTipos().add(new SelectItem("03", "Plastic"));
    }

    // Listener in b:dataTable commandButton
    public void onEdit(SelectItem flete) {
       setSelectedFlete(new SelectItem("03", "Plastic"));
    }

    public SelectItem getSelectedFlete() {
        return selectedFlete;
    }

    public void setSelectedFlete(SelectItem selectedFlete) {
        this.selectedFlete = selectedFlete;
    }

    public List<SelectItem> getTipos() {
        return tipos;
    }

    public void setTipos(List<SelectItem> tipos) {
        this.tipos = tipos;
    }
}

And the JSF file:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
  <h:head>
  </h:head>
  <h:body style="padding-top: 60px">
<h:form>
      <b:panelGrid id="panelFleEdit" columns="2">
        <b:commandButton look="info" icon="eye-open" ajax="true" process="@this" actionListener="#{fletesController.onEdit(flete)}" update="@next">
          <f:param name="disabledToggle" value="true" transient="true"/>
        </b:commandButton>

          <b:selectOneMenu class="modalFleteEdit" value="#{fletesController.selectedFlete.value}" label-col-md="8" label="Tipo:" disabled="true">
           <f:selectItems value="#{fletesController.tipos}"/>
          </b:selectOneMenu>
     </b:panelGrid>
</h:form>
  </h:body>
</html>l
modima65 commented 6 years ago

Hi, yes it's a little simplified, but let me take a look again, the least I want is make you lose time, though I spent a day trying to make it work without success. May it be a mix of object identity, the param I'm setting inside command button, and the render phase? I'll keep you informed. Thanks.

stephanrauh commented 6 years ago

¡Muchisimas gracias! BTW, if you want to tackle the problem from the other (my) side: I've uploaded my attempt to reproduce your bug in our showcase. The showcase is a simple Maven application running in a Tomcat. The only thing you might want to change is the dependency to BootsFaces (currently 1.2.1-SNAPSHOT in the pom.xml).

modima65 commented 6 years ago

Hi, again. The problem is with the <f:converter /> tag. Unfortunately, I DID simplified my initial example too much. I'm using a converter to save a pojo from selected item collection as required value, the value has already a pojo that matches one in the collection; the collection is a Map<String, Tipo> but I tried also a List<SelectItem> in vain. It's like, when b:selectOneMenu component is rendered initially with attributes disabled="true", and required="true", the converter is ignored; then, when the component's disabled attribute is updated and set to false, everything seem Ok to the eyes until form validation: the required value is missing due to converter failure. If I remove the disabled attribute at all from b:selectOneMenu, the converter works and validation succeeds. What do you suggest? Do I edit my first example? Or is there already a issue open for this case?

From your showcase:

Since BootsFaces 1.1.0, you can use converters as defined by the JavaEE documentation and described by M. K. Yong. In rare cases, this may turn out to be a breaking change. Previous versions of BootsFaces simply ignored the converter. In some case, such as issue 713, this can be surprising because JavaEE allows you to define converters via annotations. In this case, the converter isn't mentioned by the declaration directly.

The list of items can be defined as an tag. BootsFaces uses a modified version of the algorithm PrimeFaces 5.1 uses to implement . As a result, you can use almost the same way as .

Thank you.

chongma commented 6 years ago

related to #797 ?

stephanrauh commented 6 years ago

@modima65 Maybe it's a good idea to send us a reproducer - i.e. a minimal but complete project showing the bug. Among other things, "minimal" means there's no database, so all we need to do is to take your Maven project and deploy it in Tomcat or (say) Wildfly.

Alternatively, you can also debug BootsFaces yourself. More likely than not, the bug (if there's one) is in the class SelectOneMenuRenderer. If you need more hints, just tell me!