Creating JSF 2.2 Custom Component Dynamically -
i've written (well, modified) custom component radio buttons appearing within datatable based on this article. i've modified jsf 2.2 using @facesrenderer , @facescomponent tags , omitting custom tag class. works fine in xhtml page
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>
and datatable of radio buttons work correctly (they grouped row). problem arises when utilize component dynamically. have
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);
unfortunately, although datatable rendered, radio buttons aren't. blank columns appear. wondering if knows if there method should overriding in renderer. mine looks like:
@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) { homecoming customselectoneradio.getclientid(context); } else { if (customselectoneradio.getoverridename() != null && customselectoneradio.getoverridename().equals("true")) { homecoming 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(); } } homecoming partname; } } } private uicomponent getparentdatatablefromhierarchy(uicomponent uicomponent) { if (uicomponent == null) { homecoming null; } if (uicomponent instanceof uidata) { homecoming uicomponent; } else { //try find recursively in component tree hierarchy homecoming 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 author = 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"); } } }
to summarise, working when utilize custom tag in facelets/xhtml file, not when utilize dynamically, e.g.
<h:panelgroup id="dynamicpanel" layout="block" binding="#{documentcontroller.dynamicpanel}"/>
if has ideas on missing i'd grateful.
gotcha! revolved around changing renderertype
property. renderer class above, can see had set own, i.e.
public static final string renderer_type = "com.myapp.jsf.renderers.htmlcustomselectoneradiorenderer";
(1) changed to
public static final string renderer_type = "javax.faces.radio";
(2) changed xxx.taglib.xml
file reflect this, e.g.
<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) but, here's final step note. had create next constructor in uicustomselectoneradio
component. didn't work without either.
public uicustomselectoneradio() { this.setrenderertype("javax.faces.radio"); }
remember - extended component uiinput
, javax.faces.text
have been set. leaving component family
"customradio" fine.
i'm still not 100% comfortable renderer types etc., wants little info, balusc explains here.
jsf custom-component jsf-2.2
No comments:
Post a Comment