Main steps:
Create model instance: DynaFormModel model = new DynaFormModel();
Add row to regular grid: DynaFormRow row = model.createRegularRow();
Add label: DynaFormLabel label = row.addLabel(value, colspan, rowspan);
Add editable control: DynaFormControl control = row.addControl(data, type, colspan, rowspan);
Set relationship between label and control (optional): label.setForControl(control);
Repeat four last steps as many times as needed. What is could look like from UI point of view? A screenshot after a failed form validation:
The main tag is pe:dynaForm. Child tag pe:dynaFormControl matches created in Java controls by "type" attribute. This is usually a "one to many" relation. XHTML / Java (controller bean and model) code to the dynamic form above is listed below.
<h:panelGroup id="dynaFormGroup"> <p:messages id="messages" showSummary="true"/> <pe:dynaForm id="dynaForm" value="#{dynaFormController.model}" var="data"> <pe:dynaFormControl type="input" for="txt"> <p:inputText id="txt" value="#{data.value}" required="#{data.required}"/> </pe:dynaFormControl> <pe:dynaFormControl type="calendar" for="cal" styleClass="calendar"> <p:calendar id="cal" value="#{data.value}" required="#{data.required}" showOn="button"/> </pe:dynaFormControl> <pe:dynaFormControl type="select" for="sel" styleClass="select"> <p:selectOneMenu id="sel" value="#{data.value}" required="#{data.required}"> <f:selectItems value="#{dynaFormController.languages}"/> </p:selectOneMenu> </pe:dynaFormControl> <pe:dynaFormControl type="textarea" for="tarea"> <p:inputTextarea id="tarea" value="#{data.value}" required="#{data.required}" autoResize="false"/> </pe:dynaFormControl> <pe:dynaFormControl type="rating" for="rat"> <p:rating id="rat" value="#{data.value}" required="#{data.required}"/> </pe:dynaFormControl> <f:facet name="buttonBar"> <p:commandButton value="Submit" action="#{dynaFormController.submitForm}" process="dynaForm" update="_mainForm_dynaFormGroup"/> <p:commandButton type="reset" value="Reset" style="margin-left: 5px;"/> </f:facet> </pe:dynaForm> </h:panelGroup>
@ManagedBean @ViewScoped public class DynaFormController implements Serializable { private DynaFormModel model; private static List<SelectItem> LANGUAGES = new ArrayList<SelectItem>(); public DynaFormController() { model = new DynaFormModel(); // add rows, labels and editable controls // set relationship between label and editable controls to support outputLabel with "for" attribute // 1. row DynaFormRow row = model.createRegularRow(); DynaFormLabel label11 = row.addLabel("Author", 1, 1); DynaFormControl control12 = row.addControl(new BookProperty("Author", true), "input", 1, 1); label11.setForControl(control12); DynaFormLabel label13 = row.addLabel("ISBN", 1, 1); DynaFormControl control14 = row.addControl(new BookProperty("ISBN", true), "input", 1, 1); label13.setForControl(control14); // 2. row row = model.createRegularRow(); DynaFormLabel label21 = row.addLabel("Title", 1, 1); DynaFormControl control22 = row.addControl(new BookProperty("Title", false), "input", 3, 1); label21.setForControl(control22); // 3. row row = model.createRegularRow(); DynaFormLabel label31 = row.addLabel("Publisher", 1, 1); DynaFormControl control32 = row.addControl(new BookProperty("Publisher", false), "input", 1, 1); label31.setForControl(control32); DynaFormLabel label33 = row.addLabel("Published on", 1, 1); DynaFormControl control34 = row.addControl(new BookProperty("Published on", false), "calendar", 1, 1); label33.setForControl(control34); // 4. row row = model.createRegularRow(); DynaFormLabel label41 = row.addLabel("Language", 1, 1); DynaFormControl control42 = row.addControl(new BookProperty("Language", false), "select", 1, 1); label41.setForControl(control42); DynaFormLabel label43 = row.addLabel("Description", 1, 2); DynaFormControl control44 = row.addControl(new BookProperty("Description", false), "textarea", 1, 2); label43.setForControl(control44); // 5. row row = model.createRegularRow(); DynaFormLabel label51 = row.addLabel("Rating", 1, 1); DynaFormControl control52 = row.addControl(new BookProperty("Rating", 3, true), "rating", 1, 1); label51.setForControl(control52); } public DynaFormModel getModel() { return model; } public String submitForm() { ... // do something } public List<SelectItem> getLanguages() { if (LANGUAGES.isEmpty()) { LANGUAGES.add(new SelectItem("en", "English")); LANGUAGES.add(new SelectItem("de", "German")); LANGUAGES.add(new SelectItem("ru", "Russian")); LANGUAGES.add(new SelectItem("tr", "Turkish")); } return LANGUAGES; } } public class BookProperty implements Serializable { private String name; private Object value; private boolean required; public BookProperty(String name, boolean required) { this.name = name; this.required = required; } public BookProperty(String name, Object value, boolean required) { this.name = name; this.value = value; this.required = required; } // getter // setter }You see that one of important features is a buil-in support for labels. DynaForm renders labels automatically - no need to write p:outputLabel. Another feature is autoSubmit flag. It allows pass form parameters in URL, build a form on page load and submit it automatically. More highlights: expandable extended view area (grid), open / close state saving, widget's client-side API, various facets. Next screenshots demonstrate how to build dynamic forms with lables above fields and various elements like PrimeFaces separator. Two forms in this example are switched by clicking on the "Switch model" link. Note, XHTML code with pe:dynaForm stays the same, only Java model gets changed.
Explore the corresponding code in the use case Yet another forms.
You guys(PF + PF ext) are doing a great job and contribution to the JSF community, people are migrating from other plataforms because of your work!.
ReplyDeleteThanks for the GREAT work!
Thanks Oleg. This is really good component and I will use it in my product !!. Keep up the great job !!
ReplyDeleteHi Oleg,
ReplyDeleteyou did the post clearly. Love to be here and hook up with your post. keep blogging.
offshore software development company india
Hi Oleg,
ReplyDeleteI have problems with _mainForm_dynaFormGroup, this ": Cannot find component with identifier "_mainForm_dynaFormGroup" referenced from "dynaForm:j_idt101"."
can you help me?
Hi Oleg,
DeleteI can resolve the last problem, but now , I have other problem . I can reload one <p:selectOneMenu from other <p:selectOneMenu? with pe:dynaForm? you know something about it?
Oleg,
ReplyDeleteHow can i implement ajax on a dynaFormControl?
Mahendran
Hi Oleg,
ReplyDeleteReally nice post to checkout for my requirement
Hi Oleg,
ReplyDeleteis it possible to have dependent inputs (like postcode and city) via ajax events in a dynaform?
Hi Oleg,
ReplyDeleteYou are doing very good work. I have the very same question as the one before. It's about Ajax behaviour inside the dynaform. Is it possible ? Are there any thoughts about it.
Kindly yours
Laabidi
Ajax behavior inside the dynaform is not a problem for all components which are placed within the dynaform. But the pe:dynaForm itself doesn't have any Ajax behaviors. That means, attaching p:ajax to the pe:dynaForm doesn't make sense.
DeleteExcellent work Guys
ReplyDeleteHi Oleg,
ReplyDeleteIs there any thoughts to implement setting of min and max length in the addControl() API that you are exposing in near future?
Thanks,
Ananth
Why do you need min. / max. length in Java model? You can set min. / max. in XHTML via tag attributes. Model is only for layout.
ReplyDeleteWe are trying to build a Dynamic UI based on the configuration setup configured in database. (something similar like this - http://stackoverflow.com/questions/22197537/generate-a-dynamic-form-based-on-primefaces-extensions-dynaform-from-database-at) Since, the required and the value attributes are dynamic for the dynaFormControl of type = input. Since, different input fields have different min and max length and if we tie these two attributes dynamically to it. It will be useful to configure and load it on the fly. Correct me if i am wrong with this idea.
DeleteAgain. You can create a model class, say MyEntry, and define min. / max. length properties there. These properties can be accessed in XHTML via data object. See examples in the showcase please.
DeleteThanks Oleg for your prompt reply. Yes, you are correct i can do that as you suggested. I over thought about my problem statement after seeing rowspan and colspan in the addcontrol.
DeleteHi Oleg, It's me again. I have a doubt on what I am doing. I am trying to configure the id/name attribute through the model class(DynamicUIProperty) to avoid the rendering of - id="mainForm:dynaForm:r1c1reg:txt" name="mainForm:dynaForm:r1c1reg:txt". So, that we can do our java script stuff based on the id/name that we sent from the model class. I am trying something like this
DeletePlease look at the for, id and name attributes. But I end up with the following error:
Caused by: java.lang.IllegalArgumentException: Empty id attribute is not allowed
at javax.faces.component.UIComponentBase.validateId(UIComponentBase.java:542)
at javax.faces.component.UIComponentBase.setId(UIComponentBase.java:369)
at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.assignUniqueId(ComponentTagHandlerDelegateImpl.java:369)
Is there a way to solve my problem statement? I would to like to have id/name defined for each of my control rendered through my model class. Let me know your thoughts.
Thanks in advance.
pe:dynaFormControl type="input" for="#{data.id}" styleClass="dynaControl"
Deletep:inputText id="#{data.id}" name="#{data.name}" value="#{data.value}" required="#{data.required}" maxlength="#{data.maxLength}" placeholder="#{data.placeHolder}"
pe:dynaFormControl
This is the post that I was referring to in my previous post.