2009-07-19 8 views
4

Wenn ich h: selectOneRadio verwende und die Liste der Werte in einer Liste als liefert, wird der gesamte Optionsfeldabschnitt als eine einzige ununterbrochene Liste angezeigt. Ich muss es in 3 Spalten arrangieren. Ich habe versucht zu gebenAufteilen von Optionsfeldern in Spalten in 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> 

Aber es gibt keinen Unterschied in der gerenderten Abschnitt. Es ist nicht in Spalten aufgeteilt. Was mache ich falsch?

Antwort

0

Das h: panelGrid enthält nur ein untergeordnetes Element (a h: selectOneRadio), sodass es immer nur eine Spalte darstellt. Das h: selectOneRadio rendert auch eine HTML-Tabelle. Sein Renderer bietet nur zwei Layouts (lineDirection und pageDirection).

Sie haben ein paar Optionen

  • Verwendung JavaScript, um die Tabelle nach dem Laden der Seite
  • finden eine 3rd party Kontrolle zu ändern, die die Funktionalität implementiert Sie
  • Ihre eigene selectOneRadio Steuer schreiben
3

Ich habe den Code von Damo angepasst, um mit h: selectOneRadio statt h: selectManycheckbox zu arbeiten. Um es zu erhalten arbeiten Sie müssen es in Ihrem faces-config.xml registrieren, mit:

<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> 

es zu kompilieren, müssen Sie auch die JSF-Implementierung (in der Regel in einer Art von JSF-impl.jar gefunden in Ihrem App-Server).

Der Code gibt die Radiobuttons in Divs statt einer Tabelle aus. Sie können dann CSS verwenden, um sie so zu gestalten, wie Sie es möchten. Ich würde eine feste Breite zu dem checkboxDiv und inneren divs schlagen geben, und mit dann der inneren divs Anzeige als Inline-Blöcke:

div.radioButtonDiv{ 
    width: 300px; 
} 

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

, die die drei Spalten geben sollen Sie suchen

Der Code:

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; 

    } 


} 
Verwandte Themen