Reputation: 13
EDIT1:
As suggested by Valentin Jacquemin i implemented it with one List<Entry<String,String>>
however, when i now change a value, tomcat throws an error:
error message:
SEVERE: /bvDesktop_RuleOverviewAddActionNode.xhtml at line 111 and column 115 value="#{paramListKVs.value}": Property 'value' not writable on type java.lang.Object
javax.el.PropertyNotFoundException: /bvDesktop_RuleOverviewAddActionNode.xhtml at line 111 and column 115 value="#{paramListKVs.value}": Property 'value' not writable on type java.lang.Object
And the corresponding line in my xhtml:
<p:dataTable id="paramListKV" var="paramListKVs" value="#{ruleTreeBeanAddActionNode.paramListKV}" editable="true" editMode="cell">
<p:column>
<f:facet name="header">List Key</f:facet>
<h:outputText value="#{paramListKVs.key}"/>
</p:column>
<p:column>
<p:cellEditor id="paramListKVsEditTest">
<f:facet name="header">List Value</f:facet>
<f:facet name="output"><h:outputText value="#{paramListKVs.value}"/></f:facet>
--><f:facet name="input"><p:inputText value="#{paramListKVs.value}" style="width:96%" /></f:facet><--
</p:cellEditor>
</p:column>
</p:dataTable>
marked by --> and <--.
I don't know what java tries to write the code to. I'm not even sure if value="#{paramListKVs.value}"
is correct. Any ideas?
I have a particular problem i was able to solve, but i feel like my solution is more like a dirty way. I hope that there is a more elegant way to do this, but i wasn't able to find one (searched so). So here is my problem:
I'm currently creating a rule-based framework for automated processing of some files and I want to give our editors the possibility to create those rules in a nice and easy web interface.
I already have the required websites,datamodel and so on. However one particular problem is, that an Action-Rule can have a Set of Properties Key-Value
wise. I choose a TreeMap
. Now i want to be able to add
, delete
and edit
the cells in the representing datatable.
Java: createActioNode:
@ManagedBean
public class RuleTreeBeanAddActionNode {
...
private TreeMap<String,String> actionParamMap = new TreeMap<String,String>();
private String paramKeyToAdd = "";
private String paramValueToAdd = "";
private int paramKeyIndex;
private String valueToChange;
private String keyForInfo;
private UIComponent datatable;
public void addKeyValueToMap() {
if((paramKeyToAdd != null || !paramKeyToAdd.equals("")) && (paramValueToAdd != null) || !paramValueToAdd.equals("")) {
unusedActionParamKeys.remove(paramKeyToAdd);
usedActionParamKeys.add(paramKeyToAdd);
actionParamsAsListKeys.add(paramKeyToAdd);
actionParamsAsListValues.add(paramValueToAdd);
actionParamMap.put(paramKeyToAdd, paramValueToAdd);
actionParamMapEntries = new ArrayList<Entry<Integer, String>>((Collection<? extends Entry<Integer, String>>) actionParamMap.entrySet());
userSession.setAttribute("actionParamMap", actionParamMap);
userSession.setAttribute("unusedActionParamKeys", unusedActionParamKeys);
userSession.setAttribute("usedActionParamKeys", usedActionParamKeys);
userSession.setAttribute("tempSelectorWorkOn", "");
userSession.setAttribute("tempRuleId", "");
userSession.setAttribute("actionParamsAsListKeys", actionParamsAsListKeys);
userSession.setAttribute("actionParamsAsListValues", actionParamsAsListValues);
paramKeyToAdd = "";
paramValueToAdd = "";
}
}
public void setValueToChange(String valueToChange) {
DataTable dt = (DataTable)datatable;
String id = String.valueOf(paramKeyIndex);
Entry<String, String> temp = (Entry<String, String>)dt.getRowData();
actionParamMap.put((String) temp.getKey(), valueToChange);
}
//getter and setter
createActionNode.xhtml
<tr>
<td>Action Parameter </td>
<td>
<p:dataTable binding="#{ruleTreeBeanAddActionNode.datatable}"
rowKey="test"
rowIndexVar="paramKeyIndex"
id="paramKeysValues"
var="params"
value="#{ruleTreeBeanAddActionNode.actionParamMapEntries}"
editable="true"
editMode="cell">
<p:column id="keys">
<f:facet name="header">Param Key</f:facet>
<h:outputText value="#{params.key}"/>
</p:column>
<p:column id="values">
<f:facet name="header">Param Value</f:facet>
<p:cellEditor id="paramValueEdit">
<f:facet name="output"><h:outputText value="#{params.value}"/></f:facet>
<f:facet name="input"><p:inputText id="evinput" value="#{ruleTreeBeanAddActionNode.valueToChange}" style="width:96%"/></f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
</td>
</tr>
<tr><td><br/></td></tr>
<tr>
<td>Param To Value</td>
<td>
<table>
<tr>
<td>
<p:selectOneMenu id="paramKeys" value="#{ruleTreeBeanAddActionNode.paramKeyToAdd}">
<f:selectItems value="#{ruleTreeBeanAddActionNode.unusedActionParamKeys}"/>
</p:selectOneMenu>
</td>
<td>
<p:inputText id="paramValue" value="#{ruleTreeBeanAddActionNode.paramValueToAdd}"/>
</td>
</tr>
<tr>
<td></td>
<td>
<p:commandButton id="addParam" value="+" action="#{ruleTreeBeanAddActionNode.addKeyValueToMap}" update="paramKeysValues,paramKeys,paramValue"/>
</td>
</tr>
</table>
</td>
</tr>
I understood that i need to return not the map but the entry set, so that the datatable can iterarte through it. So when i edit a record in the cell, the function
#{ruleTreeBeanAddActionNode.valueToChange}
is called on a change. However to retrieve the actual record and thus the key and value to change in the map, i have to go over the UIComponent
of Datatable
, retrieve the edited record,save the map and rebuild the entry set.
So my actual question is, is this the recommended way? Did i oversee something that would make my world much easier? Has someone else implemented something like this?
Upvotes: 1
Views: 2714
Reputation: 2245
Here is the doc for UIData, which any datatable is child of:
UIData is a UIComponent that supports data binding to a collection of data objects represented by a DataModel instance, which is the current value of this component itself (typically established via a ValueExpression). During iterative processing over the rows of data in the data model, the object for the current row is exposed as a request attribute under the key specified by the var property.
Thus as you said you need an iterable object so that the datatable can loop through it and expose each element when building the table.
On the other hand, you're not leveraging on the binding feature completely here. Simply let the component doing its job and set value=#{ruleTreeBeanAddActionNode.actionParams}
, actionParams
being a List
or any other supported type. Once done, your datatable's model will reference your ruleTreeBeanAddActionNode.actionParams
elements. You don't need any further mechanism to do the sync.
See also:
UPDATE
I guess you tried to use the AbstractMap.SimpleEntry as entries of your list. This class is not JavaBean compatible though as the setValue
is not of type void
. Create your own object holding the state of your row so that you've a JavaBean compatible object and EL will be able to resolve the read/write methods correctly:
public class Entry{
private String key;
private String value;
public Entry(String key, String value) {
this.key = key;
this.value = value;
}
public String getKey() {return key;}
public String getValue() {return value;}
public void setKey(String key) {this.key = key;}
public void setValue(String value) {this.value = value;}
}
Then in your backing bean:
@ManagedBean
public class RuleTreeBeanAddActionNode {
private List<Entry> entries;
@PostConstruct
public void init() {
entries = new ArrayList<Entry>();
entries.add(new Entry("foo", "bar"));
}
public List<Entry> getEntries() { return entries; }
}
Upvotes: 1