2014-06-24 5 views
3

나는 this article에 기반한 데이터 테이블 안에 나타나는 라디오 버튼을위한 (잘 수정 된) 커스텀 컴포넌트를 작성했다. @FacesRenderer 및 @FacesComponent 태그를 사용하고 사용자 정의 태그 클래스를 생략하여 JSF 2.2에서 약간 수정했습니다. 모든 것은 내 XHTML 페이지JSF 2.2 사용자 정의 컴포넌트 동적 생성하기

xmlns:custom="http://mynamespace" 
... 
<h:dataTable id="mySampleTable3" 
      value="#{myBackingBean.sampleTable3}" 
      var="item" 
      width="100%" 
      border="1" 
      first="0">   
    <f:facet name="header"> 
     <h:panelGrid id="gridHeader3" columns="2" width="100%" > 
       <h:outputText id="outputText3" 
         value="Radios grouped in row(With our custom tag)"/> 
     </h:panelGrid> 
    </f:facet> 
    <h:column> 
     <f:facet name="header"> 
       <h:outputText value="Emp Name" /> 
     </f:facet> 
     <h:outputText id="empName" value="#{item.empName}"/> 
    </h:column>   
    <h:column> 
     <f:facet name="header"> 
       <h:outputText value="Excellent" /> 
     </f:facet> 
     <custom:customradio id="myRadioId2" 
          name="myRadioRow" 
          value="#{item.radAns}" 
          itemValue="E" />      
    </h:column>   
    <h:column> 
     <f:facet name="header"> 
        <h:outputText value="Good" /> 
     </f:facet> 
     <custom:customradio id="myRadioId3" 
          name="myRadioRow" 
          value="#{item.radAns}" 
          itemValue="G" />      
    </h:column> 
    ...  
</h:dataTable> 

에서 잘 작동 및 라디오 버튼의 데이터 테이블 (그들은 행에 의해 그룹화)가 제대로 작동합니다. 이 구성 요소를 동적으로 사용할 때 문제가 발생합니다. 그래서 있어요

HtmlPanelGrid radioGrid = (HtmlPanelGrid) getApplication() 
          .createComponent(HtmlPanelGrid.COMPONENT_TYPE); 

... 

UICustomSelectOneRadio customSelectOneRadio = (UICustomSelectOneRadio) getApplication(). 
        createComponent(UICustomSelectOneRadio.COMPONENT_TYPE); 


customSelectOneRadio.setId("rb_" + question.getQuestionId() + "_" + row + "_" + col); 
customSelectOneRadio.setName("myRadioRow"); 

String binding = "#{" + beanName + "." + propName + 
       "[\"" + question.getQuestionId().toString() + "_" + 
       subQuestion.getId() + "\"]}"; 

ValueExpression ve = getExpressionFactory(). 
        createValueExpression(getELContext(), binding, String.class); 
customSelectOneRadio.setValueExpression("value", ve); 

customSelectOneRadio.setItemValue(value); 

radioGrid.getChildren().add(customSelectOneRadio); 

불행하게도 데이터 테이블이 렌더링되지만 라디오 버튼은 아닙니다. 빈 열이 나타납니다. 렌더러에서 오버라이드해야하는 메소드가 있는지 아는 사람이 있는지 궁금합니다.

@FacesRenderer(componentFamily = UICustomSelectOneRadio.COMPONENT_FAMILY, rendererType = HTMLCustomSelectOneRadioRenderer.RENDERER_TYPE) 
public class HTMLCustomSelectOneRadioRenderer extends Renderer { 

    public static final String RENDERER_TYPE = "com.myapp.jsf.renderers.HTMLCustomSelectOneRadioRenderer"; 

    @Override 
    public void decode(FacesContext context, UIComponent component) { 
     if ((context == null) || (component == null)) { 
      throw new NullPointerException(); 
     } 

     UICustomSelectOneRadio customSelectOneRadio; 
     if (component instanceof UICustomSelectOneRadio) { 
      customSelectOneRadio = (UICustomSelectOneRadio) component; 
     } else { 
      return; 
     } 

     Map map = context.getExternalContext().getRequestParameterMap(); 
     String name = getName(customSelectOneRadio, context); 
     if (map.containsKey(name)) { 
      String value = (String) map.get(name); 
      if (value != null) { 
       setSubmittedValue(component, value); 
      } 

     } 
    } 

    private void setSubmittedValue(UIComponent component, Object obj) { 
     if (component instanceof UIInput) { 
      ((UIInput) component).setSubmittedValue(obj); 
     } 
    } 


    private String getName(UICustomSelectOneRadio customSelectOneRadio, 
      FacesContext context) { 

     UIComponent parentUIComponent 
      = getParentDataTableFromHierarchy(customSelectOneRadio); 
     if (parentUIComponent == null) { 
      return customSelectOneRadio.getClientId(context); 
     } else { 
      if (customSelectOneRadio.getOverrideName() != null 
        && customSelectOneRadio.getOverrideName().equals("true")) { 
       return customSelectOneRadio.getName(); 
      } else { 
       String id = customSelectOneRadio.getClientId(context); 
       int lastIndexOfColon = id.lastIndexOf(":"); 
       String partName = ""; 
       if (lastIndexOfColon != -1) { 
        partName = id.substring(0, lastIndexOfColon + 1); 
        if (customSelectOneRadio.getName() == null) { 
         partName = partName + "generatedRad"; 
        } else { 
         partName = partName + customSelectOneRadio.getName(); 
        } 
       } 
       return partName; 
      } 
     } 
    } 

    private UIComponent getParentDataTableFromHierarchy(UIComponent uiComponent) { 
     if (uiComponent == null) { 
      return null; 
     } 
     if (uiComponent instanceof UIData) { 
      return uiComponent; 
     } else { 
      //try to find recursively in the Component tree hierarchy 
      return getParentDataTableFromHierarchy(uiComponent.getParent()); 
     } 
    } 

    @Override 
    public void encodeEnd(FacesContext context, UIComponent component) 
      throws IOException { 
     if ((context == null) || (component == null)) { 
      throw new NullPointerException(); 
     } 

     UICustomSelectOneRadio customSelectOneRadio 
      = (UICustomSelectOneRadio) component; 

     if (component.isRendered()) { 
      ResponseWriter writer = context.getResponseWriter(); 

      writer.startElement("input", component); 
      writer.writeAttribute("type", "radio", "type"); 
      writer.writeAttribute("id", component.getClientId(context), "id"); 
      writer.writeAttribute("name", getName(customSelectOneRadio, context), "name"); 

      if (customSelectOneRadio.getStyleClass() != null && customSelectOneRadio.getStyleClass().trim(). 
        length() > 0) { 
       writer.writeAttribute("class", customSelectOneRadio.getStyleClass().trim(), "class"); 
      } 
      if (customSelectOneRadio.getStyle() != null && customSelectOneRadio.getStyle().trim().length() > 0) { 
       writer.writeAttribute("style", customSelectOneRadio.getStyle().trim(), "style"); 
      } 

     ... 

      if (customSelectOneRadio.getValue() != null 
        && customSelectOneRadio.getValue().equals(customSelectOneRadio.getItemValue())) { 
       writer.writeAttribute("checked", "checked", "checked"); 
      } 

      if (customSelectOneRadio.getItemLabel() != null) { 
       writer.write(customSelectOneRadio.getItemLabel()); 
      } 
      writer.endElement("input"); 
     } 
    } 

} 

빨리 내가 ​​Facelets의/XHTML 파일에 사용자 정의 태그를 사용할 때,이 노력을 요약,하지만하지 내가 동적으로 사용하는 경우, 예를 들면 : 광산처럼 보이는

<h:panelGroup id="dynamicPanel" layout="block" binding="#{documentController.dynamicPanel}"/> 

내가 누락 된 부분에 대한 아이디어가 있으면 감사 할 것입니다.

답변

0

Gotcha! 이 모든 것은 rendererType 속성을 바꿔 놓았습니다. 위의 렌더러 클래스에서, 당신은 내가 즉

, 내 자신으로 설정했다 볼 수 있습니다

public static final String RENDERER_TYPE = "com.myapp.jsf.renderers.HTMLCustomSelectOneRadioRenderer";

나는

public static final String RENDERER_TYPE = "javax.faces.Radio";

(2)로 변경 (1) 또한이를 반영하기 위해 xxx.taglib.xml 파일을 변경했습니다.

<namespace>http://mycomponents</namespace> 
<tag> 
    <tag-name>customradio</tag-name> 
    <component> 
     <component-type>CustomRadio</component-type> 
     <renderer-type>javax.faces.Radio</renderer-type>  /*<----- See Here */ 
    </component> 
</tag> 

(3)는하지만, 여기서주의해야 할 마지막 단계입니다. 내 UICustomSelectOneRadio 구성 요소에 다음 생성자를 만들어야했습니다. 이것도 없이는 작동하지 않았습니다.

public UICustomSelectOneRadio() { 
    this.setRendererType("javax.faces.Radio"); 
} 

는 기억 - 그래서 javax.faces.Text을 설정 한 것, UIInput에서 내 구성 요소를 확장했다. 내 component family을 "CustomRadio"로 남겨두고 괜찮 았습니다.

저는 여전히 렌더러 유형 등으로 100 % 편안하지는 않지만 약간의 정보를 원하는 사람에게는 BalusC을 잘 설명합니다. here.

관련 문제