Я написал (ну, модифицированный) настраиваемый компонент для переключателей, появляющихся внутри datatable на основе this article. Я немного изменил его для JSF 2.2, используя теги @FacesRenderer и @FacesComponent и опустив класс пользовательских тегов. Все отлично работает в моей 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>
и 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}"/>
Если у кого-то есть идеи о том, что я могу отсутствовать, я был бы признателен.