Assign 'value expression' in place of 'method expression' in JSF - jsf

In my composite component, I iterate a list<list<javaDetailClass>>. I get all my <h:commandButon> attribute's values through value expression like #{iterator.value}. But the problem comes with attribute action, where action accepts only method expression. whereas I can assign only value expression there, resulting in MethodNotFoundException
<cc:interface>
<cc:attribute name="formElements" />
</cc:interface>
<cc:implementation>
<c:forEach items="#{cc.attrs.formElements}" var="element">
<c:forEach items="#{element}" var="iterator">
<h:commandButton id="#{iterator.id}"
value="#{iterator.value}"
action="#{iterator.action}">
</h:commandButton>
</c:forEach>
</c:forEach>
</cc:implementation>
Can anyone help me in fixing this?
Thanks in advance.
UPDATE
this will be the detail class in my situation,
package com.stackoverflow.test;
public class TestData {
/*Properties based on the implementation of your composite.
Change type where it is needed*/
private String id;
private String value;
private String attributeName;
private String action;
public TestData() {
}
/*Getters and setters omitted*/
}
Bean.java simply holds an ArrayList of ArrayList. The constructor simply created five TestData objects and assigns some default value to its attributes.
package com.stackoverflow.test;
import java.util.ArrayList;
import javax.faces.bean.*;
#ManagedBean
#RequestScoped
public class Bean {
private ArrayList<ArrayList<TestData>> list = new ArrayList<ArrayList<TestData>>();
public Bean() {
ArrayList<TestData> testDataList = new ArrayList<TestData>();
TestData data;
for(int i = 0; i < 5; i++) {
data = new TestData();
data.setId("ID" + i);
data.setValue("VALUE" + i);
data.setAttributeName("ATTRIBUTE" + i);
/**this sets the action attribute of TestData with a API from some other managed bean**/
data.setAction("someOtherManagedbean.someactionAPI");
testDataList.add(data);
}
list.add(testDataList);
}
public ArrayList<ArrayList<TestData>> getList() {
return list;
}
public void setList(ArrayList<ArrayList<TestData>> list) {
this.list = list;
}
}
index.html simply calls the composite by assinging the value of "#{bean.list} to the name attribute

I'm assuming that your TestData.java has the following method public String getAction() (since I'm seeing a setAction(String)) and not
public String action(). Therefore, the reason why you are getting a MethodNotFoundException is because you are supplying the wrong method name to the action attribute. In your case it should be iterator.getAction and not iterator.action. You only supply the abbreviated names when an attribute is expecting a value expression. The interface below has been modifed.
<cc:interface>
<cc:attribute name="formElements" />
</cc:interface>
<cc:implementation>
<c:forEach items="#{cc.attrs.formElements}" var="element">
<c:forEach items="#{element}" var="iterator">
<h:commandButton id="#{iterator.id}"
value="#{iterator.value}"
action="#{iterator.getAction}">
</h:commandButton>
</c:forEach>
</c:forEach>
</cc:implementation>

Related

Using h:selectBooleanCheckbox with c:if to obtain row value of a <rich:datatable> - JSF

I'm using a <rich:datatable> to show the content of a List<Map<String, String>
In the code below, spotlightPtBindings is the List<Map<String, String> and spotlightbinding represents each Map<String, String>. In the first column, I'm showing one selectBooleanCheckBox for eah row. When a selectBooleanCheckBox is checked, I'd like to send the value of the Map<String, String> corresponding to the key "URI" as a parameter to the method: inserirBean.onSelectedCheckBox(uri), and that's why I put this value in a ui:param of name: uri. The problem here is that when I try to print the value uri received in inserirBean.onSelectedCheckBox(uri), I don't get the any output, as if it is empty. Below there's the rest of the code:
InsereDocumento.xhtml
<rich:dataTable value="#{inserirBean.spotlightPtBindings}" var="spotlightbinding">
<rich:column>
<f:facet name="header">*</f:facet>
<ui:param name="uri" value="#{spotlightbinding['URI']}"/>
<h:selectBooleanCheckbox value="#{selectionBean.selected}" />
<c:if test="#{selectionBean.selected}">
#{inserirBean.onSelectedCheckBox(uri)}"
</c:if>
</rich:column>
<c:forEach items="#{inserirBean.variableNamesPt}" var="vname">
<rich:column>
<f:facet name="header">#{vname}</f:facet>
#{spotlightbinding[vname]}
</rich:column>
</c:forEach>
</rich:dataTable> <br />
SelectionBean
package managedBeans;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
#ManagedBean
public class CheckBoxSelectionBean implements Serializable {
private transient boolean selected = false;
private static final long serialVersionUID = 1L;
public CheckBoxSelectionBean() {
// TODO Auto-generated constructor stub
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
}
InserirBean - I'm not showing here how the List<Map<String, String>> named spotlightPtBinding and how the List<String> variableNamesPt were populated, because it was a complex process, but I can tell you they are certainly populated, cause I can see their content on the screen.
#ManagedBean
public class InsereDocumentoBean implements Serializable {
private static final long serialVersionUID = 1L;
private List<String> variableNamesPt = new ArrayList<String>();
private List<Map<String, String>> spotlightPtBindings = new ArrayList<Map<String, String>>();
public List<String> getVariableNamesPt() {
return variableNamesPt;
}
public List<Map<String, String>> getSpotlightPtBindings() {
return this.spotlightPtBindings;
}
public void onSelectedCheckBox(String uri) {
System.out.println("URI: " + uri);
}
}
What may the problem be? Thank you! I'm new to JSF and need your help!
In JSF rendering is a two-step process: there's view build time and view render time.
Although they're in the same file, some tags take effect at view build time, some at render time.
JSTL tags like <c:forEach>, <c:if> and all tag handlers (including <ui:param>, see here) are evaluated at view build time, they add content to the "final" xml tree that is then rendered by JSF.
JSF HTML tags and derivates like <rich:dataTable> are evaluated at view render time, so the datatable's var is evaluated later then the <ui:param> which causes spotlightbinding not to be bound when it's assigned to uri.
Instead, I suggest you assign an ajax listener to call the function:
<h:selectBooleanCheckbox value="#{selectionBean.selected}">
<f:ajax listener="#{inserirBean.onSelectedCheckBox(spotlightbinding['URI'])}" />
</h:selectBooleanCheckbox>
Note that the listener is called whenever the value changes.

why i get null parameter value?

I have problem with parameter at my web application. At some page (index.xhtml) i have:
...
<f:metadata>
<f:viewParam name="backurl"/>
</f:metadata>
<h:form>
<h:outputLabel value="backurl: #{backurl}"/>
<h:commandButton image="/resources/graphics/poland.gif" action="#{userController.setLanguage('pl', param['backurl'])}"/>
</h:form>
setLanguage() method in userController managed bean:
public void setLanguage(String language, String backurl) {
setLang(new Locale(language));
...
}
when i run application and go to index.xhtml page i see backurl: /pages/login.xhtml
but at setLanguage method second parametr (backurl) is null when i click and debug application
Where is problem ?
why dont you use this?
<h:commandButton action="#{userController.setLanguage}">
<f:param name="param1" value="value1" />
<f:param name="backurl" value="#{backurl}" />
</h:commandButton>
and then in your method
public String setLanguage() {
Map<String,String> params =
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
String param1= params.get("param1");
String backurl= params.get("backurl");
}
#{userController.setLanguage('pl', backurl)}
this should work. (didn't test it)
there are many ways to pass parameters to a backing bean. Here is a useful article
You can store the view-param value in the managed-bean (provide accessors for the introduced backurl member, also).
<f:metadata>
<f:viewParam name="backurl" value="#{userController.backurl}" />
</f:metadata>
And then you can get rid of the second method parameter and get the backurl value from the variable in the managed-bean.
action="#{userController.setLanguage('pl')}"/>
The managed bean should look like this:
public class UserController {
private String backurl;
public String getBackurl() { return backurl; }
public void setBackurl(String backurl) { this.backurl = backurl; }
public void setLanguage(String language) {
setLocale(new Locale(language));
System.out.println(backurl); //this refers the variable in the managed-bean
}
}

JSF events not propagating from composite component with backing component

all
I've been working on a composite component for a date range. Essentially, my composite component uses two Richfaces 4.3 calendar components underneath to capture the individual date values, generate a date range (a pair of LocalDate objects). I found this blog entry which was the basis for my custom component that combines the two submitted values on the calendar into one pair value.
Everything seems to work fine and the values are getting updated. However, I'm trying to figure out how to propagate the change event to the using xhtml page for a partial render of another component, and I've been unsuccessful. I've tried everything I could think of, but I think I'm missing something.
The page:
<rich:panel>
<f:facet name="header">Calendar Date Range Component</f:facet>
<h:outputText id="out1" binding="#{calendarDateRangeTestBean.component1}"
value="#{calendarDateRangeTestBean.dateRange}" converter="localDatePairConverter" /><br/>
<h:outputText id="out2" value="#{calendarDateRangeTestBean.dateRange}" converter="localDatePairConverter" /><b>NOT WORKING</b>
<yxp:calendarDateRange id="calendarDateRange" value="#{calendarDateRangeTestBean.dateRange}"
dataModel="#{calendarDateRangeTestBean}"
valueChangeListener="#{calendarDateRangeTestBean.processValueChange}">
<f:ajax execute="#all" listener="#{calendarDateRangeTestBean.processBehaviorEvent}"/>
<!-- This doesn't seem to work???? -->
<f:ajax execute="#all" render="out2" />
</yxp:calendarDateRange>
</rich:panel>
My test managed bean:
#ViewScoped
#ManagedBean
public class CalendarDateRangeTestBean extends AbstractCalendarDateRangeDataModel implements
ValueChangeListener, Serializable {
private static Logger logger = LoggerFactory.getLogger(CalendarDateRangeTestBean.class);
private Pair<LocalDate> dateRange = Pair.of(LocalDate.now(), LocalDate.now().plusDays(7));
private UIComponent component1;
public UIComponent getComponent1() {
return component1;
}
public LocalDateRange getDateRange() {
return dateRange;
}
public void processBehaviorEvent(final javax.faces.event.AjaxBehaviorEvent event) {
logger.info("processing event " + event + ": " + event.getBehavior());
final FacesContext context = FacesContext.getCurrentInstance();
logger.info("Setting render to " + component1.getClientId(context));
// This seems to cause a rerender of the first component
context.getPartialViewContext().getRenderIds().add(component1.getClientId(context));
}
#Override
public void processValueChange(final ValueChangeEvent event) throws AbortProcessingException {
logger.info(this.toString() + ": processing value change event " + event + ": ["
+ event.getOldValue() + ":" + event.getNewValue() + "]");
}
public void setComponent1(final UIComponent component1) {
this.component1 = component1;
}
public void setDateRange(final Pair<LocalDate> dateRange) {
logger.info("Setting date range to " + dateRange);
this.dateRange = dateRange;
}
}
My composite component:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich"
xmlns:composite="http://java.sun.com/jsf/composite">
<!-- Methods exposed on rich:component are available in the __proto__ object. -->
<composite:interface componentType="com.yieldex.platform.ui.CalendarDateRange">
<composite:attribute name="value" required="true" type="demo.Pair"/>
<composite:attribute name="dataModel" required="false" type="demo.Pair" />
<composite:clientBehavior name="change" event="change" targets="startCalendar endCalendar" default="true"/>
</composite:interface>
<composite:implementation>
<h:outputStylesheet library="yieldex/platform" name="css/yieldex-platform.css" target="head" />
<div id="#{cc.clientId}" class="yxp-calendar-date-range">
<rich:calendar id="startCalendar"
binding="#{cc.startCalendar}"
styleClass="yxp-start-date-range"
converter="localDateConverter" mode="ajax"
dataModel="#{not empty cc.attrs.dataModel ? cc.attrs.dataModel.startCalendarDataModel : standardCalendarDateRangeDataModel.startCalendarDataModel}"
monthLabels="#{dateRangeMessages.monthNames}"
weekDayLabelsShort="#{dateRangeMessages.weeksShort}"
monthLabelsShort="#{dateRangeMessages.monthNames}" popup="false"
showInput="false" showFooter="false" showWeeksBar="false"
showWeekDaysBar="true" showApplyButton="false"
buttonIcon="#{resource['yieldex/platform:img/1x1-transparent.png']}"
buttonDisabledIcon="#{resource['yieldex/platform:img/1x1-transparent.png']}">
<f:facet name="weekDays"></f:facet>
<f:ajax immediate="true" execute="#all" render="#this endCalendar"/>
</rich:calendar>
<rich:calendar id="endCalendar"
binding="#{cc.endCalendar}"
styleClass="yxp-end-date-range"
converter="localDateConverter" mode="ajax"
dataModel="#{not empty cc.attrs.dataModel ? cc.attrs.dataModel.endCalendarDataModel : standardCalendarDateRangeDataModel.endCalendarDataModel}"
monthLabels="#{dateRangeMessages.monthNames}"
weekDayLabelsShort="#{dateRangeMessages.weeksShort}"
monthLabelsShort="#{dateRangeMessages.monthNames}" popup="false"
showInput="false" showFooter="false" showWeeksBar="false"
showWeekDaysBar="true" showApplyButton="false"
buttonIcon="#{resource['yieldex/platform:img/1x1-transparent.png']}"
buttonDisabledIcon="#{resource['yieldex/platform:img/1x1-transparent.png']}">
<f:facet name="weekDays"></f:facet>
<f:ajax immediate="true" execute="#all" render="startCalendar #this"/>
</rich:calendar>
</div>
</composite:implementation>
</ui:composition>
My backing component:
#FacesComponent("com.yieldex.platform.ui.CalendarDateRange")
public class YXCalendarDateRange extends UIInput implements NamingContainer {
private UICalendar startCalendarComponent;
private UICalendar endCalendarComponent;
#Override
public void encodeBegin(final FacesContext context) throws IOException {
final Pair<LocalDate> value = (Pair<LocalDate>) this.getValue();
if (value == null) {
startCalendarComponent.setValue(null);
endCalendarComponent.setValue(null);
} else {
startCalendarComponent.setValue(value.getStart());
endCalendarComponent.setValue(value.getEnd());
}
super.encodeBegin(context);
}
#Override
protected Object getConvertedValue(final FacesContext context, final Object submittedValue) {
final LocalDate startDate = (LocalDate) startCalendarComponent.getConverter().getAsObject(context,
startCalendarComponent, (String) this.startCalendarComponent.getSubmittedValue());
final LocalDate endDate = (LocalDate) endCalendarComponent.getConverter().getAsObject(context,
endCalendarComponent, (String) this.endCalendarComponent.getSubmittedValue());
if (startDate == null || endDate == null) {
return null;
} else {
if (startDate.isAfter(endDate)) {
final FacesMessage message = new FacesMessage();
message.setSeverity(FacesMessage.SEVERITY_ERROR);
message.setSummary("start date cannot be after end date");
message.setDetail("start date cannot be after end date");
throw new ConverterException(message);
}
return Pair.of(startDate, endDate);
}
}
public UICalendar getEndCalendar() {
return this.endCalendarComponent;
}
#Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
public UICalendar getStartCalendar() {
return this.startCalendarComponent;
}
#Override
public Object getSubmittedValue() {
return this;
}
public void setEndCalendar(final UICalendar endCalendarComponent) {
this.endCalendarComponent = endCalendarComponent;
}
public void setStartCalendar(final UICalendar startCalendarComponent) {
this.startCalendarComponent = startCalendarComponent;
}
}
What I see is that the valueChangedEvent is coming though. I also see my processBehaviorEvent being called, and the first outputText being rerendered as I'm calling that programmatically. But the second one doesn't seem to get rerendered. I am trying to figure out if this is a bug in Mojarra 2.1.25 or is there something fundamentally wrong with my approach. Any suggestions would be greatly appreciated.
Any client ID in <f:ajax render> is evaluated relative to the parent naming container of the component it has been attached to. In this construct, the <f:ajax> ends up being attached inside the composite component, which is by itself a naming container. However, there's no component with ID out2 inside the composite, which is the problem.
To solve it, specify the absolute client ID. For example, when it's inside a <h:form id="formId"> element:
<f:ajax execute="#all" render=":formId:out2" />
If it's more complicated, binding the component to the view and refer to its client ID dynamically:
<h:outputText id="out2" binding="#{out2}" ... />
...
<f:ajax execute="#all" render=":#{out2.clientId}" />
See also:
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"

Values of h:inputText inside ui:repeat are not processed

I want to process this form (valueChangueListener is not valid in real case).
This is the back bean:
public class TestBean extends PrivateBaseBean implements Serializable {
private List<String> strings;
#PostConstruct
public void init() {
strings = new ArrayList<String>();
strings.add("");
strings.add("");
strings.add("");
}
public void saveAction(ActionEvent event) {
StringBuilder textToShowInMessage = new StringBuilder();
for (String string : strings) {
textToShowInMessage.append(string);
textToShowInMessage.append("; ");
}
FacesMessage msg = new FacesMessage(super.getBundle().getString(
textToShowInMessage.toString()), "");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
getters... setters...
An the view:
....
<h:form>
<ui:repeat var="string" value="#{testBean.strings}">
<h:inputText value="#{string}" />
<br />
</ui:repeat>
<p:commandButton value="#{msg.save}"
actionListener="#{testBean.saveAction}" icon="ui-icon-disk"
update="#form" />
</h:form>
...
When the form is processed in the back bean string list always is blank.
How to process form intput's inside iteration, without any value changue listener?
There are some screenshots:
The same problem occurs with action or actionListener on
Your problem is not connected with PrimeFaces <p:commandButton>'s behaviour, but rather with a scoping problem that is implicilty created when using the <ui:repeat> tag.
First of all, let's depart from your example. Basically, you've got
<ui:repeat value="#{bean.strings}" var="s">
<h:inputText value="#{s}"/>
</ui:repeat>
with the backing List<String> strings.
The culprit is here: value="#{s}". The exported by <ui:repeat> variable s is visible only within its loop and it is not bound to any managed bean's property, but instead only to a local variable. Put it differently, s is not bound/equal to bean.strings[index] as one would expect and has no knowledge, as we see, where it originated from. So basically, you're off with a unilateral relationship: value from the bean is printed in your input properly, but the reverse is not happening.
The workarounds
Workaround #1: wrapper classes / model objects
The situation can be overcome by using a wrapper object for your class. In case of a string it could be a 'simple mutable string', like below:
public class MString {
private String string;//getter+setter+constructor
}
In this case the iteration will be working as predicted:
<ui:repeat value="#{bean.mstrings}" var="ms">
<h:inputText value="#{ms.string}"/>
</ui:repeat>
with the backing List<MString> mstrings.
Note that if you have your model class, like User, and will change its properties within <ui:repeat> the class itself will be effectively a wrapper, so that the properties will be set appropriately.
Workaround #2: chained property access
Another workaround consists of accessing an element of your collection directly from within a <h:inputText> tag. This way, any such property will be set by accessing the bean, then collection, then setting the property at the desired index. Excessively long, but that's how it is. As to the how question, <ui:repeat> provides for an exported current iteration status variable, varStatus, that will be used to access the array/collection in the managed bean.
In this case the iteration will also be working as predicted:
<ui:repeat value="#{bean.strings}" var="s" varStatus="status">
<h:inputText value="#{bean.strings[status.index]}"/>
</ui:repeat>
with the ordinary backing List<String> strings.
My workaround solution take the value directly from the page:
<ui:repeat id="repeat" value="#{bean.strings}" var="s" varStatus="status">
<h:inputText id="x" value="#{s.field}"/>
<h:commandLink style="margin: .5em 0" styleClass="commandLink" actionListener="#{bean.save(status.index)}" value="#{bundle.Send}"/>
</ui:repeat>
The save method:
public void save(String rowid) {
String jsParam = Util.getJsParam("repeat:" + rowid + ":x");
System.out.println("jsParam: " + jsParam); //persist...
}
The getJsParam method:
public static String getJsParam(String paramName) {
javax.faces.context.FacesContext jsf = javax.faces.context.FacesContext.getCurrentInstance();
Map<String, String> requestParameterMap = jsf.getExternalContext().getRequestParameterMap();
String paramValue = requestParameterMap.get(paramName);
if (paramValue != null) {
paramValue = paramValue.trim();
if (paramValue.length() == 0) {
paramValue = null;
}
}
return paramValue;
}

How can I do this with a custom/composite component?

I tried to ask a more specific question but I think i may have been overly specific so I'll zoom out to get a better advice.
I'm trying to create a composite/custom component that will accept two attributes
A list of strings --> names of fields
a list of lists of <String, Value> --> groups of fields with <fieldName, fieldValue>
example values:
[Street, Country, State, ZipCode]
[{(Street, Greenfield), (Country, USA)}, {(Country, Canada), (ZipCode, 3333)}]
The component will render this, based on the attributes:
The reason I am having difficulties with this component is that I don't know what's the proper way to maintain placeholders for fields that were not entered originally but can be added by the user through the component.
In the above example, for the first set, these would be State and ZipCode.
My Idea was to create a dummy object with all the fields and on submittion copy the dummy object's values to the data structure passed in the attributes.
The problem I was facing was not knowing how to read the values on component creation and altering the List passed through the attribute on submission.
I will add sample code soon (Although that shouldn't be a crucial for answering this question)
Thank you just for reading this far!! :-)
My Code (Again, not required for answering the question but may be helpful to understand my challenge)
The Composite Component Code:
<cc:interface componentType="dynamicFieldList">
<cc:attribute name="styleClass" default="fieldType" />
<cc:attribute name="form" default="#form"
shortDescription="If used, this is the name of the form that will get executed" />
<cc:attribute name="list" type="java.util.List" required="true"
shortDescription="The values of the list. The type must be List of FieldGroup" />
<cc:attribute name="groupTypes" type="java.util.List" required="true"
shortDescription="The types that will be available to choose from for each field. The type of this must be List of FieldType" />
</cc:interface>
<cc:implementation>
<h:dataTable id="table" value="#{cc.model}" var="fieldGroup">
<h:column>
<ui:repeat var="field" value="#{fieldGroup.values}">
<utils:fieldType value="#{field.value}" type="#{field.type}"/>
</ui:repeat>
</h:column>
<h:column>
<h:commandButton value="delete" action="#{cc.remove}">
<f:ajax render="#{cc.attrs.form}" execute="#{cc.attrs.form}" />
</h:commandButton>
</h:column>
</h:dataTable>
<h:commandButton value="add" action="#{cc.add}">
<f:ajax render="#{cc.attrs.form}" execute="#{cc.attrs.form}" />
</h:commandButton>
</cc:implementation>
The component bean java code:
#FacesComponent(value = "dynamicFieldGroupList")
// To be specified in componentType attribute.
#SuppressWarnings({ "rawtypes", "unchecked" })
// We don't care about the actual model item type anyway.
public class DynamicFieldGroupList extends UIComponentBase implements NamingContainer
{
private transient DataModel model;
private List<FieldGroup> displayList;
public DynamicFieldGroupList()
{
super();
List<FieldGroup> list = new ArrayList<FieldGroup>();
for (FieldGroup group : getList()){
FieldGroup currGroup = new FieldGroup("Untitled");
//Assumption - Each type may exist only once in a group.
Map<FieldType, FieldDetail> hash = new HashMap<FieldType, FieldDetail>();
for (FieldDetail detail: group.getDetails()){
hash.put(detail.getType(), detail);
}
// While creating the dummy object, insert values the exist or placeholders if they don't.
for (FieldType type : getGroupTypes()){
if (hash.containsKey(type)){
currGroup.addDetail(hash.get(type));
} else {
currGroup.addDetail(new FieldDetail(type,null));
}
}
list.add(currGroup);
}
// Assign the created list to be the displayed (dummy) object
setDisplayList(list);
}
public void add()
{
// Add a new group of placeholders
FieldGroup group = new FieldGroup("Untitled");
for (FieldType type: getGroupTypes()){
group.addDetail(new FieldDetail(type, null));
}
getList().add(group);
}
public void remove()
{
getDisplayList().remove(model.getRowData());
}
#Override
public String getFamily()
{
return "javax.faces.NamingContainer"; // Important! Required for
// composite components.
}
public DataModel getModel()
{
if (model == null)
model = new ListDataModel(getDisplayList());
return model;
}
private List<FieldGroup> getList()
{ // Don't make this method public! Ends otherwise in an infinite loop
// calling itself everytime.
return (List) getAttributes().get("list");
}
private List<FieldType> getGroupTypes()
{ // Don't make this method public! Ends otherwise in an infinite loop
// calling itself everytime.
return (List) getAttributes().get("groupTypes");
}
public void setDisplayList(List<FieldGroup> displayList)
{
this.displayList = displayList;
}
public List<FieldGroup> getDisplayList()
{
return displayList;
}
}
You can use a Map to hold the values for each group.
Map<String, Object> values = new HashMap<String, Object>();
Assuming that you've all those maps in a List<Map<String, Object>> and the field names in a List<String>, then you can get/set them all basically as follows
<ui:repeat value="#{allValues}" var="values">
<ui:repeat value="#{fieldNames}" var="fieldName">
<h:outputLabel value="#{fieldName}" />
<h:inputText value="#{values[fieldName]}" />
<br/>
</ui:repeat>
</ui:repeat>

Resources