2009-07-19 4 views
4

Когда я использую h: selectOneRadio и поставляя список значений в списке как , вся секция радиокнопки отображается как единый непрерывный список. Мне нужно расположить его в 3 колонках. Я пробовал даватьРазрыв радиокнопки в столбцах в JSF

<h:panelGrid id="radioGrid" columns="3"> 
<h:selectOneRadio id="radio1" value="#{bean.var}"> 
<f:selectItems id="rval" value="#{bean.list}"/> 
</h:selectOneRadio> 
</h:panelGrid> 

Но нет разницы в рендеринговой секции. Его не разбивают на столбцы. Что я делаю не так?

ответ

0

h: panelGrid содержит только один ребенок (h: selectOneRadio), поэтому он будет отображать только один столбец. H: selectOneRadio также отображает таблицу HTML. Его рендеринг предлагает только два макета (lineDirection и pageDirection).

У вас есть несколько вариантов

  • использование JavaScript для изменения таблицы после загрузки страницы
  • найти 3rd party управления, реализующий функциональность вы хотите
  • написать свой собственный контроль selectOneRadio
3

Я адаптировал код, данный Дамо, для работы с h: selectOneRadio вместо h: selectManycheckbox. Для того, чтобы получить его работу вы должны зарегистрировать его в гранях-config.xml с:

<render-kit> 
    <renderer> 
     <component-family>javax.faces.SelectOne</component-family> 
     <renderer-type>javax.faces.Radio</renderer-type> 
     <renderer-class>test.components.SelectOneRadiobuttonListRenderer</renderer-class> 
    </renderer> 
</render-kit> 

Чтобы скомпилировать его, вам также потребуется выполнение JSF (как правило, найти в какой-то JSF-impl.jar в вашем сервере приложений).

Код выводит радиобарабаны в divs вместо таблицы. Затем вы можете использовать CSS для их стилизации, как бы вы ни хотели. Я хотел бы предложить дать фиксированную ширину в checkboxDiv и внутренней дивы, а затем с внутренней дисплей дивы как встроенные блоки:

div.radioButtonDiv{ 
    width: 300px; 
} 

div.radioButtonDiv div{ 
    display: inline-block; 
    width: 100px; 
} 

Который должен дать 3 колонки, которые вы ищете

код:

package test.components; 

import java.io.IOException; 
import java.lang.reflect.Array; 
import java.util.Collection; 
import java.util.Iterator; 

import javax.faces.component.NamingContainer; 
import javax.faces.component.UIComponent; 
import javax.faces.component.UISelectMany; 
import javax.faces.component.UISelectOne; 
import javax.faces.context.FacesContext; 
import javax.faces.context.ResponseWriter; 
import javax.faces.model.SelectItem; 

import com.sun.faces.renderkit.RenderKitUtils; 
import com.sun.faces.renderkit.html_basic.MenuRenderer; 
import com.sun.faces.util.MessageUtils; 
import com.sun.faces.util.Util; 

/** 
* This component ensures that h:selectOneRadio doesn't get rendered using 
* tables. It is adapted from the code at: 
* http://www.blog.locuslive.com/?p=15 
* 
* To register it for use, place the following in your faces config: 
* 
* <render-kit> 
*  <renderer> 
*   <component-family>javax.faces.SelectOne</component-family> 
*   <renderer-type>javax.faces.Radio</renderer-type> 
*   <renderer-class>test.components.SelectOneRadiobuttonListRenderer</renderer-class> 
*  </renderer> 
* </render-kit> 
* 
* The original comment is below: 
* 
* ----------------------------------------------------------------------------- * 
* This is a custom renderer for the h:selectManycheckbox 
* It is intended to bypass the incredibly sucky table based layout used 
* by the standard component. 
* 
* This layout uses an enclosing div with divs for each input. 
* This gives a default layout similar to a vertical layout 
* The layout can then be controlled by css 
* 
* This renderer assigns an class of "checkboxDiv" to the enclosing div 
* The class and styleClass attributes are then applied to the internal 
* divs that house the inputs 
* 
* The following attributes are ignored as they are no longer required when using CSS: 
* - pageDirection 
* - border 
* 
* Note that I am not supporting optionGroups at this stage. They would be relatively 
* easy to implement with another enclosing div 
* 
* @author damianharvey 
* 
*/ 
public class SelectOneRadiobuttonListRenderer extends MenuRenderer { 

    public void encodeEnd(FacesContext context, UIComponent component) 
      throws IOException { 

     if (context == null) { 
      throw new NullPointerException(
        MessageUtils.getExceptionMessageString(MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, 
                     "context")); 
     } 
     if (component == null) { 
      throw new NullPointerException(
        MessageUtils.getExceptionMessageString(MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, 
                     "component")); 
     } 

     // suppress rendering if "rendered" property on the component is 
     // false. 
     if (!component.isRendered()) { 
      return; 
     } 

     ResponseWriter writer = context.getResponseWriter(); 
     assert(writer != null); 

     writer.startElement("div", component); 
     if (shouldWriteIdAttribute(component)) { 
      writeIdAttributeIfNecessary(context, writer, component); 
     } 
     writer.writeAttribute("class", "radioButtonDiv", "class"); 

     Iterator items = RenderKitUtils.getSelectItems(context, component).iterator(); 
     SelectItem curItem = null; 
     int idx = -1; 
     while (items.hasNext()) { 
      curItem = (SelectItem) items.next(); 
      idx++; 
      renderOption(context, component, curItem, idx); 
     } 

     writer.endElement("div"); 

    } 

    protected void renderOption(FacesContext context, UIComponent component, SelectItem curItem, int itemNumber) 
      throws IOException { 

     ResponseWriter writer = context.getResponseWriter(); 
     assert(writer != null); 

     // disable the check box if the attribute is set. 
     String labelClass = null; 
     boolean componentDisabled = Util.componentIsDisabled(component); 

     if (componentDisabled || curItem.isDisabled()) { 
      labelClass = (String) component. 
        getAttributes().get("disabledClass"); 
     } else { 
      labelClass = (String) component. 
        getAttributes().get("enabledClass"); 
     } 

     writer.startElement("div", component); //Added by DAMIAN 

     String styleClass = (String) component.getAttributes().get("styleClass"); 
     String style = (String) component.getAttributes().get("style"); 

     if (styleClass != null) { 
      writer.writeAttribute("class", styleClass, "class"); 
     } 
     if (style != null) { 
      writer.writeAttribute("style", style, "style"); 
     } 

     writer.startElement("input", component); 
     writer.writeAttribute("name", component.getClientId(context), "clientId"); 
     String idString = component.getClientId(context) + NamingContainer.SEPARATOR_CHAR + Integer.toString(itemNumber); 
     writer.writeAttribute("id", idString, "id"); 
     String valueString = getFormattedValue(context, component, curItem.getValue()); 
     writer.writeAttribute("value", valueString, "value"); 
     writer.writeAttribute("type", "radio", null); 

     Object submittedValues[] = getSubmittedSelectedValues(context, component); 
     boolean isSelected; 

     Class type = String.class; 
     Object valuesArray = null; 
     Object itemValue = null; 
     if (submittedValues != null) { 
      valuesArray = submittedValues; 
      itemValue = valueString; 
     } else { 
      valuesArray = getCurrentSelectedValues(context, component); 
      itemValue = curItem.getValue(); 
     } 
     if (valuesArray != null) { 
      type = valuesArray.getClass().getComponentType(); 
     } 

     // I don't know what this does, but it doens't compile. Commenting it 
     // out doesn't seem to hurt 
     // Map<String, Object> requestMap = context.getExternalContext().getRequestMap(); 
     // requestMap.put(ConverterPropertyEditorBase.TARGET_COMPONENT_ATTRIBUTE_NAME, 
     //  component); 

     Object newValue = context.getApplication().getExpressionFactory(). 
       coerceToType(itemValue, type); 

     isSelected = isSelected(newValue, valuesArray); 

     if (isSelected) { 
      writer.writeAttribute(getSelectedTextString(), Boolean.TRUE, null); 
     } 

     // Don't render the disabled attribute twice if the 'parent' 
     // component is already marked disabled. 
     if (!Util.componentIsDisabled(component)) { 
      if (curItem.isDisabled()) { 
        writer.writeAttribute("disabled", true, "disabled"); 
      } 
     } 

     // Apply HTML 4.x attributes specified on UISelectMany component to all 
     // items in the list except styleClass and style which are rendered as 
     // attributes of outer most table. 
     RenderKitUtils.renderPassThruAttributes(writer, component, new String[] { "border", "style" }); 
     RenderKitUtils.renderXHTMLStyleBooleanAttributes(writer, component); 

     writer.endElement("input"); 
     writer.startElement("label", component); 
     writer.writeAttribute("for", idString, "for"); 
     // if enabledClass or disabledClass attributes are specified, apply 
     // it on the label. 
     if (labelClass != null) { 
      writer.writeAttribute("class", labelClass, "labelClass"); 
     } 
     String itemLabel = curItem.getLabel(); 
     if (itemLabel != null) { 
      writer.writeText(" ", component, null); 
      if (!curItem.isEscape()) { 
       // It seems the ResponseWriter API should 
       // have a writeText() with a boolean property 
       // to determine if it content written should 
       // be escaped or not. 
       writer.write(itemLabel); 
      } 
      else { 
       writer.writeText(itemLabel, component, "label"); 
      } 
     } 
     writer.endElement("label"); 

     writer.endElement("div"); //Added by Damian 
    } 

    // ------------------------------------------------- Package Private Methods 


    String getSelectedTextString() { 

     return "checked"; 

    } 

    /** For some odd reason this is a private method in the MenuRenderer superclass 
    * 
    * @param context 
    * @param component 
    * @return 
    */ 
    private Object getCurrentSelectedValues(FacesContext context, 
      UIComponent component) { 

     if (component instanceof UISelectMany) { 
      UISelectMany select = (UISelectMany) component; 
      Object value = select.getValue(); 

      if (value instanceof Collection) { 

       Collection<?> list = (Collection) value; 
       int size = list.size(); 
       if (size > 0) { 
        // get the type of the first element - Should 
        // we assume that all elements of the List are 
        // the same type? 
        return list.toArray((Object[]) Array.newInstance(list.iterator().next().getClass(), size)); 
       } 
       else { 
        return ((Collection) value).toArray(); 
       } 

      } 
      else if (value != null && !value.getClass().isArray()) { 
       logger.warning("The UISelectMany value should be an array or a collection type, the actual type is " + value.getClass().getName()); 
      } 

      return value; 
     } 

     UISelectOne select = (UISelectOne) component; 
     Object returnObject; 
     if (null != (returnObject = select.getValue())) { 
      Object ret = Array.newInstance(returnObject.getClass(), 1); 
      Array.set(ret, 0, returnObject); 
      return ret; 
     } 
     return null; 

    } 

    /** For some odd reason this is a private method in the MenuRenderer superclass 
    * 
    * @param context 
    * @param component 
    * @return 
    */ 
    private Object[] getSubmittedSelectedValues(FacesContext context, UIComponent component) { 

     if (component instanceof UISelectMany) { 
      UISelectMany select = (UISelectMany) component; 
      return (Object[]) select.getSubmittedValue(); 
     } 

     UISelectOne select = (UISelectOne) component; 
     Object returnObject; 
     if (null != (returnObject = select.getSubmittedValue())) { 
      return new Object[] { returnObject }; 
     } 
     return null; 

    } 

    /** For some odd reason this is a private method in the MenuRenderer superclass 
    * 
    * @param itemValue 
    * @param valueArray 
    * @return 
    */ 
    private boolean isSelected(Object itemValue, Object valueArray) { 

     if (null != valueArray) { 
      if (!valueArray.getClass().isArray()) { 
       logger.warning("valueArray is not an array, the actual type is " + valueArray.getClass()); 
       return valueArray.equals(itemValue); 
      } 
      int len = Array.getLength(valueArray); 
      for (int i = 0; i < len; i++) { 
       Object value = Array.get(valueArray, i); 
       if (value == null) { 
        if (itemValue == null) { 
         return true; 
        } 
       } 
       else if (value.equals(itemValue)) { 
        return true; 
       } 
      } 
     } 
     return false; 

    } 


}