components - How to create dynamic JSF form fields -


i have found similar questions this one, there many ways can done made me more confused.

we getting xml file reading. xml contains information on form fields needs presented.

so created custom dynamicfield.java has information need:

public class dynamicfield {   private string label; // label of field   private string fieldkey; // key identify field   private string fieldvalue; // value of field   private string type; // can input,radio,selectbox etc    // getters + setters. } 

so have list<dynamicfield>.

i want iterate through list , populate form fields looks this:

<h:datatable value="#{dynamicfields}" var="field">     <my:somecustomcomponent value="#{field}" /> </h:datatable> 

the <my:somecustomcomponent> return appropriate jsf form components (i.e. label, inputtext)

another approach display <my:somecustomcomponent> , return htmldatatable form elements. (i think maybe easier do).

which approach best? can show me links or code shows how can create this? prefer complete code examples, , not answers "you need subclass of javax.faces.component.uicomponent".

since origin not xml, javabean, , other answer doesn't deserve edited totally different flavor (it may still useful future references others), i'll add answer based on javabean-origin.


i see 3 options when origin javabean.

  1. make use of jsf rendered attribute or jstl <c:choose>/<c:if> tags conditionally render or build desired component(s). below example using rendered attribute:

    <ui:repeat value="#{bean.fields}" var="field">     <div class="field">         <h:inputtext value="#{bean.values[field.name]}" rendered="#{field.type == 'text'}" />         <h:inputsecret value="#{bean.values[field.name]}" rendered="#{field.type == 'secret'}" />         <h:inputtextarea value="#{bean.values[field.name]}" rendered="#{field.type == 'textarea'}" />         <h:selectoneradio value="#{bean.values[field.name]}" rendered="#{field.type == 'radio'}">             <f:selectitems value="#{field.options}" />         </h:selectoneradio>         <h:selectonemenu value="#{bean.values[field.name]}" rendered="#{field.type == 'selectone'}">             <f:selectitems value="#{field.options}" />         </h:selectonemenu>         <h:selectmanymenu value="#{bean.values[field.name]}" rendered="#{field.type == 'selectmany'}">             <f:selectitems value="#{field.options}" />         </h:selectmanymenu>         <h:selectbooleancheckbox value="#{bean.values[field.name]}" rendered="#{field.type == 'checkone'}" />         <h:selectmanycheckbox value="#{bean.values[field.name]}" rendered="#{field.type == 'checkmany'}">             <f:selectitems value="#{field.options}" />         </h:selectmanycheckbox>     </div> </ui:repeat> 

    an example of jstl approach can found @ how make grid of jsf composite component? no, jstl absolutely not "bad practice". myth leftover jsf 1.x era , continues long because starters didn't understand lifecycle , powers of jstl. point, can use jstl when model behind #{bean.fields} in above snippet not ever change during @ least jsf view scope. see jstl in jsf2 facelets... makes sense? instead, using binding bean property still "bad practice".

    as <ui:repeat><div>, doesn't matter iterating component use, can use <h:datatable> in initial question, or component library specific iterating component, such <p:datagrid> or <p:datalist>. refactor if necessary big chunk of code include or tagfile.

    as collecting submitted values, #{bean.values} should point map<string, object> precreated. hashmap suffices. may want prepopulate map in case of controls can set multiple values. should prepopulate list<object> value. note expect field#gettype() enum since eases processing in java code side. can use switch statement instead of nasty if/else block.


  2. create components programmatically in postaddtoview event listener:

    <h:form id="form">     <f:event type="postaddtoview" listener="#{bean.populateform}" /> </h:form> 

    with:

    public void populateform(componentsystemevent event) {     htmlform form = (htmlform) event.getcomponent();     (field field : fields) {         switch (field.gettype()) { // it's easiest if it's enum.             case text:                 uiinput input = new htmlinputtext();                 input.setid(field.getname()); // must unique!                 input.setvalueexpression("value", createvalueexpression("#{bean.values['" + field.getname() + "']}", string.class));                 form.getchildren().add(input);                 break;             case secret:                 uiinput input = new htmlinputsecret();                 // etc...         }     } } 

    (note: not create htmlform yourself! use jsf-created one, 1 never null)

    this guarantees tree populated @ right moment, , keeps getters free of business logic, , avoids potential "duplicate component id" trouble when #{bean} in broader scope request scope (so can safely use e.g. view scoped bean here), , keeps bean free of uicomponent properties in turn avoids potential serialization trouble , memory leaking when component held property of serializable bean.

    if you're still on jsf 1.x <f:event> not available, instead bind form component request (not session!) scoped bean via binding

    <h:form id="form" binding="#{bean.form}" /> 

    and lazily populate in getter of form:

    public htmlform getform() {     if (form == null) {         form = new htmlform();         // ... (continue code above)     }     return form; } 

    when using binding, it's important understand ui components request scoped , should absolutely not assigned property of bean in broader scope. see how 'binding' attribute work in jsf? when , how should used?


  3. create custom component custom renderer. not going post complete examples since that's lot of code after tight-coupled , application-specific mess.


pros , cons of each option should clear. goes easy , best maintainable hard , least maintainable , subsequently least reuseable best reuseable. it's pick whatever best suits functional requirement , current situation.

noted should there absolutely nothing only possible in java (way #2) , impossible in xhtml+xml (way #1). possible in xhtml+xml in java. lot of starters underestimate xhtml+xml (particularly <ui:repeat> , jstl) in dynamically creating components , incorrectly think java "one , only" way, while ends in brittle , confusing code.


Comments

Popular posts from this blog

android - getbluetoothservice() called with no bluetoothmanagercallback -

sql - ASP.NET SqlDataSource, like on SelectCommand -

ios - Undefined symbols for architecture armv7: "_OBJC_CLASS_$_SSZipArchive" -