1

Я пытаюсь создать составной компонент, который позволит пользователю переключаться между h: singleSelectMenu и h: selectManyListbox. У меня это работает. Он работает до тех пор, пока поле значений указывает на Collection ... он НЕ работает, если поле значения равно null.Как создать составной компонент JSF, который связывает коллекцию как с h: selectOneMenu, так и с h: selectManyListbox?

singleMultiSelect.xhtml

<?xml version="1.0" encoding="US-ASCII"?> 
<!DOCTYPE html> 
<ui:composition 
    xmlns:f="http://xmlns.jcp.org/jsf/core" 
    xmlns:h="http://xmlns.jcp.org/jsf/html" 
    xmlns:ui="http://java.sun.com/jsf/facelets" 
    xmlns:cc="http://java.sun.com/jsf/composite" 
    xmlns:c="http://java.sun.com/jstl/core" 
    xmlns:ace="http://www.icefaces.org/icefaces/components" 
    > 

    <cc:interface componentType="singleMultiSelect"> 

     <!-- The initial list of objects --> 
     <cc:attribute name="list" type="java.util.List" required="true"/> 
     <!-- The selected objects --> 
     <cc:attribute name="selected" type="java.util.Collection" required="true"/> 
     <!-- whether to display the selectOneMenu (true) or selectManyBox (false) --> 
     <cc:attribute name="singleSelect" type="java.lang.Boolean" 
        required="false" default="true"/> 

    </cc:interface> 
    <cc:implementation> 

     <span id="#{cc.clientId}"> 

      <ace:checkboxButton id="singleSelectChkBx" 
           value="#{cc.attrs.singleSelect}"> 
       <ace:ajax render="#{cc.clientId}"/> 
      </ace:checkboxButton>      

      <h:selectOneMenu id="selectOneMenu" 
          rendered="#{cc.attrs.singleSelect}" 
          value="#{cc.singleSelected}">      
       <f:selectItems value="#{cc.attrs.list}"/> 
      </h:selectOneMenu> 

      <h:selectManyListbox id="selectManyListbox" 
           rendered="#{! cc.attrs.singleSelect}" 
           value="#{cc.attrs.selected}"> 
       <f:selectItems value="#{cc.attrs.list}"/> 
      </h:selectManyListbox> 

     </span> 

    </cc:implementation> 
</ui:composition> 

SingleMultiSelect.java

public class SingleMultiSelect extends UINamingContainer {  

    public SingleMultiSelect() { 
     super(); 
    }   

    /** 
    * Converts the Object selected within the selectOneMenu to the list 
    * used by the component. 
    * 
    * @param singleSelected 
    */ 
    public void setSingleSelected(Object singleSelected) { 
     getSelected().clear(); 
     if(singleSelected != null) { 
      getSelected().add(singleSelected); 
     } 
    } 

    /** 
    * Converts the collection used by the component to a single 
    * Object selected within the selectOneMenu. 
    * 
    * @return 
    */ 
    public Object getSingleSelected() { 
     return getSelected().size() > 0 ? getSelected().iterator().next() : null; 
    }  

    private Collection getSelected() { 
     return (Collection) getAttributes().get("selected"); 
    } 
} 

Я пытался писать на атрибуты карты, но это не сработало

public void setSingleSelected(Object singleSelected) { 
    HashSet selected = new HashSet();   
    selected.add(singleSelected); 
    ((Collection) getAttributes()).put("selected", selected); 
} 

ответ

2
getAttributes().put("selected", selected); 

Вы в основном переопределяете базовый объект ValueExpression#{cc.attrs.selected} с HashSet. Другими словами, выражение EL стало «жестко запрограммированным» значением и больше не может доходить до свойства bean.

Вы должны получить ValueExpression и вызвать установщика по вызову setValue().

getValueExpression("selected").setValue(context.getElContext(), selected); 

Unrelated к конкретной задаче, при реализации компоненты подложки, то лучше думать, как компонент пользовательского интерфейса, а не поддержка компоненты. Не манипулируйте моделью напрямую (составные атрибуты), а составные компоненты составного компонента вы достигаете через binding. Более того, не трогайте геттеры/сеттеры. Заменить <h:selectOneMenu value>, как показано ниже:

<h:selectOneMenu binding="#{cc.singleSelected}" ...> 
private UISelectOne singleSelected; // +getter+setter 

@Override 
public void processUpdates(FacesContext context) { 
    super.processUpdates(context); 

    if (getAttributes().get("singleSelect") == Boolean.TRUE) { 
     HashSet selected = new HashSet(); 
     if (singleSelected.getValue() != null) { 
      selected.add(singleSelected.getValue()); 
     } 
     getValueExpression("selected").setValue(context.getELContext(), selected); 
    } 
} 

@Override 
public void encodeBegin(FacesContext context) throws IOException { 
    if (getAttributes().get("singleSelect") == Boolean.TRUE) { 
     Collection selected = (Collection) getAttributes().get("selected"); 
     if (selected != null && !selected.isEmpty()) { 
      singleSelected.setValue(selected.iterator().next()); 
     } else { 
      singleSelected.setValue(null); 
     } 
    } 

    super.encodeBegin(context); 
} 
Смежные вопросы