the Datatable is displaying only the last item added, it seems that every time i press the commandButton the method rewrites the list, what can I do to avoid that?
JSF
<p:commandButton action="#{productoBean.setPedidoActual()}" value="Agregar" update="dt"/>
</p:panelGrid>
<p:dataTable value="#{productoBean.pedidoActual}" var="pedi">
<p:column headerText="Nombre">
<h:outputText value="#{pedi.descripcion}"/>
</p:column>
</p:dataTable>
Bean
public void setPedidoActual() {
Producto pro = productoFacade.find(idProducto);
listPedidoActual.add(pro);
}
public List<Producto> getPedidoActual() {
return listPedidoActual;
}
Your setPedidoActual() method seems like to receive only one item based on the facade service find(idProducto), is that correct? Have you checked what the remote service returns? Probably there is in fact just one record.
Beside that, try to rename your setter/getter from
getPedidoActual() / setPedidoActual()
into
getListPedidoActual() setListPedidoActual()
Now your method names are consistent with your attribute.
EDIT: What happened to the panelGrid tag? Have you purposely omitted or where does it start?
Related
I am using primefaces 4.
I am using an editable table and when I edit a cell, a listener method is called passing a CellEditEvent
Like this
public void onCellEdit(CellEditEvent event) {
/*
* The rowIndex here can be changed according to the sorting/filtering.
* FilteredData starts as null, but primefaces initializes it, so you
* don't have to check for NPE here
*/
int alteredRow = event.getRowIndex();
UIColumn o = event.getColumn();
System.out.println(this.filteredData.get(event.getRowIndex()).get(columns.get(0)));
}
So far, so good.
The event has a getRowIndex()
But it does not have a getColumnIndex().
Instead, it has a getColumn() method that returns a UIColumn object.
The problem is, while debugging, I could not find a way to get any column information (name, id, etc)
I can hack the column to have some unique ID like this
<p:ajax event="cellEdit" listener="#{myMB.onCellEdit}"/>
<c:forEach items="#{myMB.columns}" var="column" varStatus="loop">
<p:column id="col#{loop.index}" headerText="#{column}" sortBy="#{column}" filterBy="#{column}" filterMatchMode="contains"/>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{dataRow[column]}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{dataRow[column]}" />
</f:facet>
</p:cellEditor>
</p:column>
</c:forEach>
But still I can't find a way to retrieve the column id from the CellEditEvent
So, assuming that a cell is something that has a row and a column, I have to ask
How do I retrieve the column of an edited cell in a CellEditEvent?
ps. I feel I am missing something, because no one would create a cell event without providing the row and the column, right?
update - it seems I can get the ID like
org.primefaces.component.column.Column o = (org.primefaces.component.column.Column)event.getColumn();
still, this seems like a hack for me. I am still interested in more elegant solutions for this ;-)
You can get the column by referring back to the column header that you passed.
In bean you could do this:
public void onCellEdit(CellEditEvent event) {
int alteredRow = event.getRowIndex();
String column_name;
column_name=event.getColumn().getHeaderText();
// now you can use this to identify the column we are working on.
}
Using getColumnId() or getColumnKey() returns the column Id but with primefaces code added to it - making it difficult to work with.
If you use p:columns rather than p:column - which is also more readable - event.getColumn() returns a DynamicColumn that implements UIColumn. Then you can use:
((DynamicColumn)event.getColumn()).getIndex()
to determine the column index. There is also a column.isDynamic() to check validity.
Using the header would need further code and might be more inefficient.
I found only one way to do this. On the xhtml, add an id to the column:
<p:column id="myColumn">
...
</p:column>
In the backing bean,column.getColumnKey() will return a generated id that contains the id you set in the xhtml (something like j_idt30:j_idt32:0:contratoReal). Thus, you can do this:
public void onCellEdit(CellEditEvent event) {
if (event.getColumn().getColumnKey().endsWith("myColumn")
}
There a several related question on this topic on SO and elsewhere, but I couldn't find a definitive answer on this specific question.
I have a p:dataTable and I want the possibility to click on a row and open a detail page (a new page, not a dialogue or window).
I have solved it this way (which I have from the primefaces website, for some reason it is no longer there: http://web.archive.org/web/20101001223235/http://www.primefaces.org/showcase/ui/datatableRowSelectionInstant.jsf):
<p:dataTable var="order" value="#{orderBean.orders}" selection="#{orderBean.selectedOrder}" selectionMode="single" rowKey="#{order.number}">
<p:ajax event="rowSelect" listener="#{orderBean.orderSelect}"/>
<p:column ... />
</p:dataTable>
The navigation is then executed in the bean:
public void orderSelect(SelectEvent event) {
ConfigurableNavigationHandler nh = (ConfigurableNavigationHandler)FacesContext.getCurrentInstance().getApplication().getNavigationHandler();
nh.performNavigation("orderDetail?faces-redirect=true");
}
My Question: is there a way of doing this just inside JSF without the help of a backing bean?
I am also asking because they removed the code exmaple from the primefaces site, which might be an indication that this is not the right way of doing something like that.
Wrap the cell(s) of interest in a simple <h:link>.
<p:column>
<h:link outcome="orderDetail">
...
</h:link>
</p:column>
Use if necessary CSS display:block on the link to let it span the entire cell. You can if necessary pass request parameters using a nested <f:param>.
since it is an ajax request, typically the request/response is used to re-render some components in the web page. What you could do is
<p:ajax event="someventofintrest" onsuccess="javascript:myjsmethod();"></p:ajax>
and
<p:remotecommand name="myjsmethod" action="#{mybean.mybeanmethod}" />
and in the backing bean
public String mybeanmethod(){
return "mynewpage"; // Navigate away to mynewpage.xhtml
}
HTH.
As I didn't find a really perfect solution, this is how I do it now.
I have now a "navigator" class like this
#Component
public class Navigator {
public void nav(String page) {
UIHelper.navigateTo(page);
}
}
And I call this class from my ajax event:
<p:ajax event="rowSelect" listener="#{navigator.nav('orderDetail')}"/>
As I said, not really perfect, but I like the fact that I don't have to write code in my backing bean. (Of course I have to write code for the Navigator, but that I can re-use.)
I have to put radio and chechbox controls in primefaces's 2.2.1 datatable but not as a selection mode controls. I want to bind that controls as a values for the backing bean.
For example:
A have a list of some configurations and in that list only one configuration can be active at one time (radiobox) but every single configuration can be active or not (selectbox).
Datatable doesn't have to be editable, because I will change values in another window. Only controls should be in the datatable.
Is that possible?
Yes, it is definitely possible I do this all the time in my datatables. However, you need to keep in mind that each row will require identification. You can do this with objects or parameters to your listener:
//Backing Bean
#ViewScoped
public class TestBean
{
private ArrayList<Element> elements;
TestBean(){...}
public ArrayList<Element> getElements(){...} //Initialize things here
public class Element
{
/* getter/setter and initialization assumed */
private boolean selected;
private String radioSelection = "one";
private String[] radioChoices = new String[]{"one", "two", "three"};
public void selectMe(ActionEvent evt)
{
System.out.println("Selected -> " + this);
}
}
}
//HTML
<p:dataTable value="testBean.elements" var="element">
<p:column>
<p:commandButton value="Select" actionListener="#{element.selectMe}"
</p:column>
<p:column>
<h:selectBooleanCheckbox value="#{element.selected}" />
</p:column>
<p:column>
<h:selectOneRadio value="#{element.radioSelection}">
<f:selectItems
value="#{element.radioChoices}"
var="item"
itemLabel="#{item}"
itemValue="#{item}"
/>
</h:selectOneRadio>
</p:column>
</p:dataTable>
You can (and might want to) use a parameter using the ID from the element or whatever your preferred pattern is. The key is remembering that each row has its own id and you're creating a set of elements, not a single element. That's where you're most likely to get bound up. Seeing as how each button is a first class citizen you should be able to whatever you want with it.
Edit:
I added a Radio/Checkbox example. It sounds like you're new to JSF so I'd advise reading up on the SelectItem class and run through how combo-boxes etc... work. The key to remember (as I stress above) is that you're rendering a lot of components so if you share a value it can easily lead to behavior you don't want. Encapsulate everything and you're usually in good shape.) You can also look at bindings as a possible solution. It all depends on where you'd rather write your code.
I'm trying to use dataModel instead of binding dataTable and have this issue. At the last column there is a commandButton which should be used for delete item from database. But when I press it, the java method isn't started.
Part of xhtml (reduced code):
<h:form>
<rich:extendedDataTable
id="table"
var="fItem"
value="#{myFood.model}"
selectionMode="none">
<rich:column width="150px">
<f:facet name="header">Datum:</f:facet>
<h:outputText value="#{fItem.date}"/>
</rich:column>
<rich:column>
<h:commandButton id="save" action="#{myFood.delete}" value="delete"/>
</rich:column>
<f:facet name="footer">
<h:commandButton id="btnTest" action="#{myFood.test}" value="test"/>
</f:facet>
</rich:extendedDataTable>
</h:form>
Part of MyFood.java:
public void delete()
{
System.out.println("TEST");
try
{
DaoCrud.delete(model.getRowData(), 'P');
}
catch (Exception e) {.....}
}
public void test()
{
System.out.println("TEST");
}
But even "TEST" is not writen to console!
Where could be the problem?
UPDATE: I've updated code examples (facet & test()), it works. Everything works fine until I've tried using dataModel private DataModel<Item> model;...
When I simply move the same commandButton to the facet, it works.
If the bean is request scoped, then you need to ensure that exactly the same model is been created during bean's (post)construction of the form submit request as it was during displaying the initial form.
private List<Item> list;
private DataModel<Item> model;
#PostConstruct
public void init() {
list = itemService.list();
model = new ListDataModel<Item>(list);
}
JSF will namely iterate over the model during the apply request values phase to determine the button pressed so that it can be invoked during the invoke application phase.
If preserving the model in the subsequent request isn't exactly trivial due to some business restrictions (e.g. missing parameters, etc), then you need to put the bean in the view scope by marking it #ViewScoped instead of #RequestScoped. This works only if you're using JSF 2.0.
#ManagedBean
#ViewScoped
public class MyBean {}
Alternatively, since you're using RichFaces, you could also use <a4j:keepAlive> for this. Put this somewhere in the same page as the form:
<a4j:keepAlive beanName="#{myBean}" />
This does effectively the same as #ViewScoped does in JSF 2.0.
It should be under <h:form>
Your delete() method should return an Object. It won't be called if the signature is not correct. "signature must match java.lang.Object action()". See here.
As far as I remember you can just return null if you want to stay at the page.
public String delete()
{
System.out.println("TEST");
try
{
DaoCrud.delete(model.getRowData(), 'P');
}
catch (Exception e) {.....}
return null;
}
You might want to use the actionListener attribute with its corresponding method if you dont want to use the method outcome for navigation. Also consider to use a <a4j:commandButton> if you want to reRender something after the actionListener has been executed.
I have the next code to load a set of images whose streams are in a datamodel called names. My problem is when I declare the var inside the p:datatable tag seems like has nothing. Any idea?
thx!
<p:dataTable value="#{controlador.names}" var="nombre" rendered="true">
<p:column rendered="true">
<h:outputText value="#{nombre.stream}"/>
<p:graphicImage value="#{nombre.stream}"/>
</p:column>
</p:dataTable>
The p:graphicImage uses another request so you need to pass an identifier to the managedBean like this.
<p:dataTable value="#{productManaged.products}" var="productIterated">
<p:column>
<f:facet name="header">
<h:outputText value="#{product.pic}"/>
</f:facet>
<p:graphicImage value="#{productManaged.dynamicProductImage}">
<f:param name="product_id" value="#{productIterated.id}"/>
</p:graphicImage>
</p:column>
</p:dataTable>
Another thing that you should take care is to return something in the StreamedContent or is gonna fail. Do something like this:
public StreamedContent getDynamicProductImage() {
String id = FacesContext.getCurrentInstance()
.getExternalContext().getRequestParameterMap().get("product_id");
if(id!=null && this.products!=null && !this.products.isEmpty()){
Integer productId = Integer.parseInt(id);
for(Product productTemp:this.products){
if(productTemp.getId().equals(productId)){
return new DefaultStreamedContent(
new ByteArrayInputStream(productTemp.getImage()),
productTemp.getMimeType());
}
}
}
return new DefaultStreamedContent(
new ByteArrayInputStream(this.products.get(0).getImage()),
this.products.get(0).getMimeType()); //if you return null here then it won't work!!! You have to return something.
}
or you can read this thread http://primefaces.prime.com.tr/forum/viewtopic.php?f=3&t=4163
After wasting hours of going the the process of implementing the many solutions I found for this issue (i.e. including a param or attribute), The only solution I managed to find that actually works can be found here: Serving Dynamic Content with PrettyFaces
Remove the <h:outputText>. You can read a stream only once. It cannot be re-read another time.
As to the p:graphicImage part, you need to feed it with a value of DefaultStreamedContent. Also see this blog entry.