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?
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:
Using Data-Bound Table Components
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; }
}
Related
I have a <h:dataTable> with columns defined as this
<h:column>
<f:facet name="header">
<h:outputText value="Price"/>
</f:facet>
<h:outputText value="#{p.price}" rendered="#{not p.editable}"></h:outputText>
<h:inputText value="#{p.price}" rendered="#{p.editable}"></h:inputText>
</h:column>
The <h:dataTable> is populated successfully with
<h:dataTable id="userTable" value="#{gnome.productList}"
var="p">
The backing bean #gnome is a #ViewScoped bean, and the productList is loaded in a postconstructor and has a normal getter.
#PostConstruct
public void init() {
productList = gnomeFacade.findAll();
}
public List<Gnome> getProductList() {
return productList;
}
The <h:inputText> is rendered when an <h:commandLink> is pressed, and it allows me to modify the data in the fields. The data is then supposed to be saved using a <h:commandButton> defined outside the <h:dataTable>,
<h:commandButton value="Save changes!" action="#{gnome.saveAction}"/>
which invokes this method
public String saveAction() {
System.out.println("DEBUG: Trying to save edited gnome...");
for (Gnome g : productList) {
gnomeFacade.edit(g);
}
return null;
}
I have added some debug printouts in the gnomeFacade.edit() method, to be able to view what data is being merged. None of the properties in the productList entities are being saved with their new values. My initial thought was that the <h:dataTable> was reiterating over the values of the productList, but since I have it loaded in a postconstructor, that should not be the issue?
Why aren't the values of the properties changing when I change the values in the <h:inputText>?
Edit:
Full .xhtml document:
https://pastee.org/75t3e
Please read to the end, there are many EDITS I have this piece of JSF code:
<h:form>
<h:dataTable class="table-striped" var="_product"
value="#{productManager.products}"
border="1"
binding="#{productManager.table}">
<h:column>
<f:facet name="header">Product</f:facet>
#{_product.name}
</h:column>
<h:column>
<f:facet name="header">Available Units</f:facet>
#{_product.stock}
</h:column>
<h:column>
<f:facet name="header">Category</f:facet>
#{_product.category}
</h:column>
<h:column>
<f:facet name="header">Price</f:facet>
#{_product.price}
</h:column>
<h:column>
<f:facet name="header">Description</f:facet>
#{_product.description}
</h:column>
<h:column>
<f:facet name="header">Select</f:facet>
<h:commandButton class="btn btn-primary" value="Select"
action="#{productManager.selectProduct}"/>
</h:column>
</h:dataTable>
</h:form>
<h:form>
<h:outputLabel for="productName">Selected Product: </h:outputLabel>
<h:inputText value="#{productManager.selectedDesiredCategory}"/>
<h:commandButton value="Filter category" action="#{productManager.filterProductsByCategory}"/>
<h:outputText id="productName" value="#{productManager.selectedName}"/><br/>
<h:outputLabel for="units">Units: </h:outputLabel>
<h:inputText id="units" value="#{productManager.selectedUnits}"/>
<h:commandButton value="Add to basket" action="#{productManager.addToBasket(accountManager.username)}"/><br/>
<h:outputText rendered="#{productManager.availableMessages}"
value="#{productManager.message}"/>
</h:form>
The #{productManager.filterProductsByCategory} commandbutton redirects to this java method:
public void filterProductsByCategory() {
this.products = controller.obtainProductListByCategory(selectedDesiredCategory);
showMessage("Filtered by selected category");
}
Here I update the content of the products list with the new set of filtered-by-category products to display them in the view. The thing is the page is not reloading to display the new content. How is this achieved?
EDIT: The showMessage method is actually displaying in the view, so the page IS reloading, but for some reason the table is not updating. Maybe it's a problem with the data the query is returning, I'm actually researching.
EDIT: The query is returning good results, as my debugging process confirmed, but the webpage is not reloading the data properly in the table.
EDIT: I found out something really weird. This is the code the JSF page is referencing to:
public void filterProductsByCategory()
{
filtered = true;
products = controller.obtainProductListByCategory(selectedDesiredCategory);
showMessage("Filtered by selected category");
}
I'm now using a boolean value to actually know when I have to deliver a filtered list (See why in the code below) This is the getter of the products list:
public List<Product> getProducts()
{
if(filtered)
{
filtered = false;
return products;
}
products = controller.obtainProductList();
return products;
}
Here if it's true it should just send the actual filtered products variable. But for some reason it's looping again and again inside the method (even after the return statement inside the if) and sending all the products to the view again. Why is this even happening?
By default, JSF calls the getter methods as much as they're used in the view. For example, for your List<Product> products field and its respective getter, if #{productManager.products appears twice in your view i.e. in the Facelets code, then the getter will be executed twice as well. For this reason, getter and setter methods in managed bean should be as clean as possible and should not contain any business logic involved.
Basically, you should retrieve the product list from database once, after creating the managed bean and before the view render time. To achieve this, you can use #PostConstruct annotation to decorate a void method that will be executed after the bean is created.
In code:
#ManagedBean
#ViewScoped
public class ProductManager {
private List<Product> products;
#PostConstruct
public void init() { //you can change the method name
//if you manually handle the controller, initialize it here
//otherwise, let it be injected by EJB, Spring, CDI
//or whichever framework you're working with
products = controller.obtainProductList();
}
public List<Product> getProducts() {
//plain getter, as simple as this
//no business logic AT ALL
return this.products;
}
public void filterProductsByCategory() {
filtered = true;
products = controller.obtainProductListByCategory(selectedDesiredCategory);
//I guess this method logs a message or something...
showMessage("Filtered by selected category");
}
}
More info
Why JSF calls getters multiple times
Why use #PostConstruct?
I have a page with a datatable which have to display various informations about Mailbox objects. One of these informations is the owner of the Mailbox which is stored by its id in Mailbox object. In output I solved this with a method in backing bean that retrieve the username by the mailbox object. In input I thought to use autocomplete with pojo but I can't exactly realize how do this.
My jsf page:
<p:dataTable id="dataTable" value="#{bean.mailboxes}" var="m" editable="true">
<!-- other table -->
<p:column headerText="Owner">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{bean.userByMailbox(m)}" />
</f:facet>
<f:facet name="input">
<!-- here comes autocomplete -->
</f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
And my bean:
public class Bean {
// Other properties and methods
List<Mailbox> mailboxes;
public List<Mailbox> getMailboxes() {
if (mailboxes == null) {
Query q = em.createNamedQuery("Mailbox.findAll");
mailboxes = q.getResultList();
}
return mailboxes;
}
public User getUserByMailbox(Mailbox m) {
Query q = em.createNamedQuery("User.findByUsrId");
q.setParameter("usrId", m.getUsrId());
return (User)q.getSingleResult();
}
}
Thank you all!
Your model is wrong.
In Mailbox, replace
#Column
private Long usrId;
by
#ManyToOne
#JoinColumn(name="usrId")
private User user;
This way you can just use#{m.user} instead of #{bean.userByMailbox(m)}. This way the property is also writable (perhaps you actually got a PropertyNotWritableException while attempting to use this EL expression in <p:autoComplete value>; in the future questions tell that so instead of asking an overly generic question).
Note that this concrete problem has essentially nothing to do with JSF nor <p:autoComplete>.
I am using primefaces for not so long and Ive found that I cant use a <p:commandButton /> because it just can't reach the method, the method is ok, I tried it out of the table (and the subtable) and it works perfectly there (everything is inside a form) , the problem is that I need the user to be able to select all the subtable, so, I thought maybe with a button that could be possible, but seems like subtable doesn't allow that, any other way I can do this? or maybe I have to use another way for call my method from a subtable, anybody knows about it?
Thanks
some of my code
<h:form>
<p:messages id="messages" showDetail="true" autoUpdate="true" closable="true" />
<p:dataTable id="case" var="ticket" value="#{CaseBean.selectedCase.tickets}">
<p:columnGroup>
<p:row>
<p:column> Action:</p:column>
<p:column>
<!-- This doesn't work, removed. -->
<p:commandButton value="Aprove" action="#{CaseBean.acept()}">
</p:commandButton>
</p:column>
</p:row>
</p:columnGroup>
<p:subTable var="detail" value="#{ticket.detail}">
<f:facet name="header">
Resume:
</f:facet>
<!-- some data... -->
<p:column>
<!-- doesn't work either -->
<p:commandButton value="Aprove" action="#{CaseBean.aceptTicket()}">
</p:commandButton>
</p:column>
<!-- show my data -->
The table works perfectly, it shows all the data, the log files doesn't show any error, so, when I tried to write my commandButton out of the table it worked perfectly, if I cant write it inside a subtable its ok, but , how could I write it in the table? it doesn't show up there either.
you welcome :)
But if i was you I wouldn't use subtables, Ill think for another solution..maybe Ill do it this way, ill use two different data tables, the first contains the parent list and the second one contains the child list elements, and every selection made triggers an update of the second table...I tried it on my IDE and it works just fine
<h:form id="form">
<p:dataTable var="cas" value="#{beanCase.myListOfCase}"
selection="#{beanCase.selectedCase}" rowKey="#{cas.idCase}"
selectionMode="single">
<p:ajax event="rowSelect" update=":form:TicketTable" />
<p:column headerText="Id Case">
<h:outputText value="#{cas.idCase}" />
</p:column>
<p:column headerText="Case Name ">
<h:outputText value="#{cas.caseName}" />
</p:column>
<p:column headerText="Case Detail">
<h:outputText value="#{cas.caseDetail}" />
</p:column>
<p:column headerText="Action">
<p:commandButton value="Accept Case" update=":form:TicketTable"></p:commandButton>
</p:column>
</p:dataTable>
<p:dataTable id="TicketTable" var="ticket"
value="#{beanCase.selectedCase.tickets}">
<p:column headerText="Ticket Number">
<h:outputText value="#{ticket.idTicket}" />
</p:column>
<p:column headerText="Ticket Details">
<h:outputText value="#{ticket.labelTicket}" />
</p:column>
<p:column headerText="show">
<h:outputText value="#{ticket.show}" />
</p:column>
<p:column headerText="this show is brought to you by">
<h:outputText value="#{ticket.sponsor}" />
</p:column>
<p:column headerText="Make a Reservation">
<p:commandButton value="Buy" action="#{beanCase.buyTicket()}">
<f:setPropertyActionListener value="#{ticket}"
target="#{beanCase.selectedTicket}" />
</p:commandButton>
</p:column>
</p:dataTable>
before that you must create the data model classes for the Case and ticket
public class CaseDataModel extends ListDataModel<Case> implements
SelectableDataModel<Case> {
CaseDAO caseDAO = new CaseDAO();
public CaseDataModel() {
}
public CaseDataModel(List<Case> cases) {
super(cases);
}
#Override
public Case getRowData(String arg0) {
List<Case> listOfMyObjet = (List<Case>) caseDAO.findAll();
for (Case obj : listOfMyObjet) {
if (String.valueOf(obj.getIdCase()).equals(arg0))
;
return obj;
}
return null;
}
#Override
public String getRowKey(Case arg0) {
return String.valueOf(arg0.getIdCase());
}
}
The first columnGroup is not rendered because in your first row the number of columns is 2, one for "action" and the other for the commandButton while in your subtable you just used two rows one for "Resume" and other contains only one Column for the other commandButton.
The number of columns should be the same in every row, so you must use colspan or rowspan to make sure of that.
As for the rest using a DataTable will do the job, I didn't understand what you wanna do exactly but I all assume that you want to select myObject from displayed list of objects within a dataTable. So in order to achieve that, the UidataTable must return an object to the backed Bean.
public class myObjectDataModel extends ListDataModel<myObject> implements SelectableDataModel<myObject> {
public myObjectDataModel() {
}
public myObjectDataModel(List<myObject> data) {
super(data);
}
#Override
public myObject getRowData(String rowKey) {
List<myObject> listOfMyObjet = (List<myObject>) yourDao.getListOfmyOjects();//get your list
for(myObject obj : listOfMyObjet) {
if(obj.getIdObject().equals(rowKey))
return obj;
}
return null;
}
#Override
public Object getRowKey(myObject obj) {
return obj.getIdObject();
}
}
The backed bean:
public class tableBean {
private List<myObject> _Objects;
private myObjectDataModel myListOfObjects;
private myObject selectedObject;
//getters and setters
public tableBean(){
myObjectDataModel = new myObjectDataModel(_Objects);
}
//...
}
xhtml:
<p:dataTable id="table" var="case"
value="#{tableBean.myObjectDataModel}"
selection="#{tableBean.selectedObject}" selectionMode="single"
rowKey="#{case.IdObject}">
<p:column>
<p:commandButton value="
Aprove" action="#{tableBean.someMethod()}">
</p:commandButton>
</p:column>
</p:dataTable>
and make sure to use Ajax — commandButton update attribute, or <p:ajax> — to refresh your UI.
Try removing the p:columnGroup from your JSF page. You don't need it for this (and this might be the cause of your problem). Think of it like this: a table exists of rows and rows exist of columns. ;-)
The #{CaseBean} has got to be in the view scope in order to get this to work, or if you want to keep it request scoped, the #{CaseBean.selectedCase.tickets} has to prepared in the (post)constructor on some request parameters so that it's exactly the same as it was during displaying the table.
When the form is submitted, JSF will namely reiterate over the table in order to find the command component responsible for the action. However, if the bean is request scoped and the value behind #{CaseBean.selectedCase} or #{CaseBean.selectedCase.tickets} is not the same as it was during displaying the table, then JSF won't be able to identify the button which invoked the action.
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated - point 4 applies to you
I'm getting the error javax.el.PropertyNotFoundException: /member/apps/cms/edit.xhtml #228,49 value="#{props.key}": Property 'key' not found on type java.util.HashMap$Values when trying to display the datatable below.
<p:dataTable id="properties" var="props" value="#{contentEditorBacking.properties}" editable="true">
<p:column headerText="Property">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{props.key}" />
</f:facet>
<f:facet name="input">
<h:inputText value="#{props.key}" />
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Value">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{props.value}" />
</f:facet>
<f:facet name="input">
<h:inputText value="#{props.value}" />
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Edit">
<p:rowEditor />
<!-- Need to put an update on here yet -->
<p:commandLink styleClass="ui-icon ui-icon-trash" id="deleteProperty" actionListener="#{contentEditorBacking.deleteProperty}">
<f:attribute name="key" value="#{props.key}" />
</p:commandLink>
</p:column>
</p:dataTable>
Here's the relevant part of my contentEditorBacking:
#ManagedBean
#ViewScoped
public class ContentEditorBacking {
private Map<String, Properties> properties = new LinkedHashMap<String, Properties>();
public Collection<Properties> getProperties() throws Exception{
return properties.values();
}
public static class Properties{
private String key;
private String value;
public Properties(String key, String value) {
super();
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#Override
public String toString() {
return "key=" + key + ", value=" + value + "";
}
}
}
How can i access the key value from my properties map?
Until the upcoming JSF 2.2, the <h:dataTable>/<p:dataTable> doesn't support Collection<E>. It only supports among others List<E>.
You need to replace
public Collection<Properties> getProperties() throws Exception{
return properties.values();
}
by
private List<Properties> propertiesAsList;
public List<Properties> getProperties() throws Exception{
return propertiesAsList;
}
and somewhere directly after map's initialization do this
propertiesAsList = new ArrayList<Properties>(properties.values());
(note: don't do it inside the getter!)
In the JSF code, you are trying to access the key property of the thing returned by getProperties() method, which is the entire collection. You need to iterate through the props variable.
The dataTable must receive a Collection (for example, a List). Map doesn't implement the Collection interface. You should convert your map into a list and modify it, then convert the list back into your map. Here's a good link showing how to do it:
Display HashMap Content in JSF Page
Of course, I won't recommend you to add logic in the getter/setter, instead use 2 different attributes and keep the getter and setter the cleanest possible way.
Your properties class needs to implement the map interface here: http://docs.oracle.com/javase/6/docs/api/java/util/Map.html
The better question is though, why are you creating your own class? Java offers a Properties class in the SDK: http://docs.oracle.com/javase/7/docs/api/java/util/Properties.html
EDIT: Update my answer per request of OP
Change the following line, then fix the compile errors in Eclipse:
public static class Properties{
to:
public static class Properties implements Map<String, String> {
EDIT #2: Actually my answer is probably wrong. The OP didn't post his entire xhtml file, and I made an assumption that was incorrect.