I have a dynamic data table in JSF which has multiple input elements which can be of various data types. The input is always a text control, but can contain numeric or text data. To handle this, each field retrieves its converterId from the backing bean:
<h:dataTable id="indexFieldTable" value="#{indexFieldBean.indexField}" var="item">
<h:column id="column">
<h:inputText id="inputID" value="#{item.value}">
<f:converter id="ifConverter" converterId="#{item.converter}" />
<f:validator id="ifValidator" validatorId="#{item.validator}" />
</h:inputText>
</h:column>
</h:dataTable>
However, when this is rendered, I get this error: Expression Error: Named Object: ' not found.
If I hard code the converterId to a known value, it works fine:
<f:converter id="ifConverter" converterId="stringConverter" />
How can I dynamically configure the converterId?
The f:
tags are specific to the component, not to the iterated item. At view build time (when the components get populated in component tree of the view), the #{item}
isn't available. It's only available during render time. You really need to attach their values to the parent bean, not the iterated item.
To fix this, first alter the Field
class (which is represented by #{item}
) to have fullworthy Converter
and Validator
properties (you could just create them upon Field
's construction).
public class Field {
private Converter converter;
private Validator validator;
// ...
}
Then alter the bean to wrap the collection of those fields in a DataModel
and have generic convert/validate methods which delegates to the currently iterated item in the DataModel
which is available by DataModel#getRowData()
:
public class Bean {
private List<Field> fields;
private DataModel<Field> fieldModel;
public Bean() {
fields = loadItSomehow();
fieldModel = new ListDataModel<Field>(fields);
}
public Converter getFieldConverter() {
return fieldModel.getRowData().getConverter();
}
public void validateField(FacesContext context, UIComponent component, Object value) throws ValidatorException {
fieldModel.getRowData().getValidator().validate(context, component, value);
}
// ...
}
Finally change the input field in the view as follows to bind the h:dataTable
's value to the DataModel
and the converter/validator to those of the parent bean which in turn delegates the call to the currently iterated item:
<h:dataTable value="#{bean.fieldModel}" var="field">
<h:column>
<h:inputText value="#{field.value}" converter="#{bean.fieldConverter}" validator="#{bean.validateField}" />
...
Noted should be that this complexity is not due to the nature of JSF, but due to the very specific functional requirement you have there. Normally, the h:dataTable
is to be used to represent tabluar data, not to generate a dynamic form.