Richfaces extendeddatatable sorting problem - jsf

I am developing a web app using JSF, RichFaces, EJB3, Hibernate and Seam.
I have an extended data table and showing a list (say userList) which has multi columns in it. Moreover, because of that this datatable is selectable, I want to keep the selected row indexes even if the sorting is changed by the user.
In other words of what I mean is that when the sorting of columns is changed, the order of row indexes is changed as well. Therefore, I want to invoke an action when the user clicks on sorting on each time. I tried many ways, but could nt find a solution to achieve it yet.
Do you have any idea about which listener or method is being called when sorting is clicked by the user in rich extendeddatatable? I cant understand what the point is in that...
Any help would be appreciated.
Many Thanks,
Baris

A code sample would have been nice, but it sounds like you have a separate list that contains the selected indices, and only update that list on a selection event.
Have you considered having the selection state live with the data object via a bean:
public DataBean {
private DataModel model;
private boolean selected;
//standard getters and setters omitted
}
JSF code:
<h:column>
<h:selectBooleanCheckbox value="dataBean.selected">
<a4j:support event="onclick" ajaxsingle="true" />
</h:selectBooleanCheckbox>
</h:column>
Tie your selection state to the model like this and sorting won't be an issue at all.

Related

Primefaces Data Table actionListener for inline cell editing

How do I execute code when the user clicks a cell in a data table? Similarly to listener and actionListener on a p:commandButton.
For example
<p:commandButton oncomplete="PF('editProductDialog').show()"
actionListener="#{bean.doStuffToGetASelectOneMenuReadyforTheEditProductDialog()}" />
public void doStuffToGetDialogReady() {
//query databases to get select item list
}
The database is only queried when/if the user clicks the commandButton
But for p:dataTable inline cell editing how to I call code that would query database to get select items only when they click the data table cell to make an edit?
<p:cellEditor>
<f:facet name="output"/>
<f:facet name="input">
<p:selectOneMenu>
<f:selectItems value="#{bean.someListSpecificToThisUser}" />
</p:selectOneMenu>
</f:facet>
</p:cellEditor>
I've been populating the someListSpecificToThisUser selectItems list in the #PostConstruct init() method
#PostConstruct
public void init() {
//code specific to the page and datatable
someListSpecificToThisUser = service.queryValuesForUser(user);
}
but if the user never clicks the cell to edit the selectOneMenu value then I hit the database and stored the list in memory for no reason. Or should I not worry about the overhead?
In case of cell editing of a p:dataTable there are a few events you can use:
Event
Fired
cellEdit
When a cell is edited.
cellEditCancel
When a cell edit is cancelled e.g. with escape key
cellEditInit
When a cell edit begins.
All taking a org.primefaces.event.CellEditEvent as the listener parameter.
You could use the cellEditInit method to populate the list when it is still null. Downside is that this requires an Ajax call on each edit init.
An other option you have is to store the list in a SessionScoped user bean, which will cost you some memory.
The option to pick depends on the size of the list, how much time it takes to fetch the list and how many edits you expect. If you don't expect much edits, use an Ajax listener to populate the list. If the list is long and takes some time to load, I would switch to a p:autoComplete field.
See also:
https://primefaces.github.io/primefaces/10_0_0/#/components/datatable?id=ajax-behavior-events
How to choose the right bean scope?
https://www.primefaces.org/showcase/ui/input/autoComplete.xhtml

How to check if instance entity has been modify in the view?

I need a guide here.
Let's say that I'm fetching some records from db an I'm populating a ui datatable with those records.
The datatable can modify the values of the records as its columns are inputs.
<p:dataTable value="#{videogames.videogameList}" var="vg" >
<p:column headerText="Name">
<p:inputText value="#{vg.name}" />
</p:column>
</p:dataTable>
How can I know if some row was modify in order to update the value in the database?
Should I check each element in the list and compare it to a temporal arraylist with the original values? Is there a more "elegant" way to do this?
Do you know any tutorial or docs that can help me to learn all this.
Thanks!
I am working with Java, JSF, primafaces and JPA.
I wish I could post it as a comment, but I lack the rep for it. I hope it serves as an answer (since you've asked for sources to learn it).
I work with PrimeFaces as well, but personally I haven't dealt with editable rows yet. Skimming over the links I give below, what you want should be doable with a RowEditEvent.
The PrimeFaces showcase is sort of a tutorial in and of itself. Here is the link for editable datatables:
http://www.primefaces.org/showcase/ui/data/datatable/edit.xhtml
Navigate through the xhtml and .java examples. It should bootstrap you in the right direction.
PrimeFaces documentation is a great source of info as well:
http://www.primefaces.org/docs/guide/primefaces_user_guide_5_3.pdf
There is an Ajax event called rowEdit that should help you. There is complementing event called rowEditCancel to detect when the user backs out of an edit.
The primefaces website offers a user guide that goes into a fair amount of detail for data tables and the rest of the framework. This is the link for the latest version 5.3.
primefaces 5.3 users guide
I think I found a solution for this case.
What I did, was to add an ajax listener with event="change", to the inputtext that can modify the value of the row, so everytime the value changes, the listener will pass the row as a param to a method, and the method will add the row to a list:
videogames.xhtml
<p:column headerText="Nombre">
<p:inputText value="#{vj.nombre}">
<!--this is the added listener-->
**<f:ajax event="change" listener="#{videojuegos.rowSelectedTest(vj)}" />**
</p:inputText>
</p:column>
<!-- **Button that calls the method for updating the modify entities columns**-->
<p:commandButton value="Actualizar" actionListener="#{videojuegos.updateVideojuego()}"/>
The managed bean receives it, and adds it to a list:
VideoGamesManagedBean.java
List <Videojuego> videojuegoUpdate = new ArrayList<Videojuego>();
//adds the modify row to a list
public void rowSelectedTest(Videojuego videojuego){
videojuegoUpdate.add(videojuego);
}
//calls the method in the EJB for merging each object in the list
public void updateVideojuego(){
if(videojuegoUpdate != null && !videojuegoUpdate.isEmpty() ){
vjbean.mergeVideojuegoList(videojuegoUpdate);
//after merging, cleans up the arraylist.
videojuegoUpdate.clear();
}
}
and last, the EJB iterates through the list and merge each object
VideoGameBean.java
#PersistenceContext
private EntityManager em;
public void mergeVideojuegoList(List<Videojuego> listVideojuegoUpdate){
for(Videojuego vjUpdate : listVideojuegoUpdate ){
em.merge(vjUpdate);
}
}
NOTE:
the only "problem" for this is, if I modify several times the same column before I hit the commandbutton "Actualizar", the list will grow up with the same row. But the merge method will take the last "version" of the column. So for our needs, it is ok.
Thanks for the previous answers, regards!!
If you know any better method or find any corner case, let me know!!

How to use rich:dataTable with row selection without binding

I'm currently migrating a legacy project from JSF 1 (with RichFaces 3) to JSF 2 (with RichFaces 4). The project has several rich:dataTables with checkboxes next to the items. At the bottom of the page, there are a few action buttons to so something with all selected items (add to favorites, export as PDF, ...).
The checkboxes are the reason why the rich:dataTables have a binding to the corresponding UI beans. But most of the UI beans are session-scoped. In between, I've learned that binding in combination with session-scope is not a good idea. And indeed, I'm having lots of "duplicate ID" errors that go away if I change the scope to "request". But it's not that easy. These beens have some state that needs to be preserved between requests and an elaborated state initialization and cleanup logic.
I think I have two options:
change the beans to request-scope, do some massive refactoring by extracting the state into some new "stateObjects" to be saved in a new "sessionBean", and completely rewrite the state logic
remove the bindings, but how can I determine which entries of the rich:dataTable have their checkboxes selected?
Curiosly, the session-scope and bindings worked together very well with JSF 1. And the decision for making the beans session-scoped was made a long time before I took over the project.
You can remove binding and change actions (bean scope changing not needed).
1) Simple case: data table with list of items and after row selection detail for selected item is displayed
Following example uses Javascript (storing item ID in bean and calling action for presenting data related to this ID):
<a4j:jsFunction name="selectRow" action="#{locationAction.showSelectedLocation}">
<a4j:param name="locationId" assignTo="#{locationAction.selectedLocationId}" />
</a4j:jsFunction>
<rich:dataTable id="locationTable"
value="#{locationAction.locationList}" var="location"
rows="#{referenceData.recordsPerPage}"
onrowclick="selectRow('#{location.locationId}')">
...
</rich:dataTable>
2) Case with multiple check boxes and action button:
<rich:dataTable id="productTable" var="res"
value="#{productPicker.pickerList}">
...
<rich:column>
<h:selectBooleanCheckbox id="selectChck" value="#{res.selected}" />
</rich:column>
...
</rich:dataTable>
<a4j:commandButton value="#{msg.detachSelected}"
action="#{productPicker.deleteSelectedFromPickerList}"
render="picker" />
where item list is private List<PickerItem> pickerList; and item is from
public class PickerItem {
private Long id; // with getter and setter
// private Record item; // with getter and setter
private boolean selected; // with getter and setter
}
In my code there are equals and hashCode methods as pat of PickerItem class, but it should works without it too.

PrimeFaces paginator selection

I have a PrimeFaces (5) DataTable and like to store the page size selection in the view, so that the user sees the same number of rows when he returns to the view.
But all I see from documentation is that there is a page event which can be captured, but which won't give me the currently selected page size. The closest I got was getting the event's source (the DataTable) and get the rows attribute, but it only contains the number of rows before applying the new value.
Here on SO, I found a solution here, but it seems to me not the best way to implement it having to use some inline JQuery stuff.
It seems to me a not-so-exotic feature to persist the page size selection within the session, so there must be a good solution for it, I assume?
As you already noticed, the page event is being fired before the selected number of rows has been applied to the table. At the moment, there is no event being fired after changing the number of rows.
However, there is a possible workaround:
bind your datatable to the backing bean
Use AJAX page-event without any listener. Instead, call a <p:remoteCommand> after ajax request is complete.
Add your actionListener method to the <p:remoteCommand>.
Within this method, check the datatable's number of rows. It's the new value.
Keep in mind, page event is not only fired when changing the number of rows, but also on page change.
Example:
XHTML/JSF
<h:form>
<p:remoteCommand name="pageChanged" actionListener="#{tableBean.onPageChanged}"/>
<p:dataTable binding="#{tableBean.table}" paginator="true" rowsPerPageTemplate="5,10,20" rows="5">
<p:ajax event="page" process="#none" oncomplete="pageChanged()" />
<!-- columns here -->
</p:dataTable>
</h:form>
TableBean.java
private DataTable table;
public void onPageChanged(){
int numRows = table.getRows();
// ...
}
//getter/setter for table

Disable and empty an input field after an AJAX call using JSF and Richfaces

I am using richfaces 4.2.0.Final and have the following situation: within a rich:dataTable, in which each row describes an article in a shopping cart, I have an input field
in which the user can input the quantity she wants to order. As soon as the user focuses on this input field, I have to perform some controls on the server (using Ajax) and if
the controls fail, I must empty the field and disable it.
My solution:
<rich:dataTable var="article" value="#{cart.articles} >
...
<rich:column>
<h:panelGroup id="orderQty">
<h:inputText id="qtyInput" value="#{article.qty}" disabled="#{article.controlsFailed}">
<a4j:ajax event="focus" bypassUpdates="true"
listener="#{requestBean.doAjaxControls(article)}"
execute="#this" render="qtyInput " />
</h:inputText>
</h:panelGroup>
#RequestScoped
#Named
public class RequestBean{
public void doAjaxControls(Article article){
boolean everyThingOK = doControls();//....
if (!everyThingOK){
article.setControlsFailed(true);
article.setQty(null);
} else {
article.setControlsFailed(false);
}
}
}
Before coming to this solution I tried several other combinations of execute/render, without succeeding in what I need (for example, I tried to use execute="#none" as I don't want
the value of qty to be updated on the server when I perform the ajax call, but this won't work).
My problem is I know this solution is not perfect: when I focus on a position for which the control will fail, and I am faster to type in a quantity than the server performing the controls, the field will be disabled and the server value for article#qty still set to null, but I will see the value I typed in until the next rendering of qtyInput will happen.
More strangely, if I execute this code on JBoss EAP 6.0.0.GA (AS 7.1.2.Final-redhat-1, which includes the module jboss-jsf-api_2.1_spec-2.0.2.Final-redhat-1),
every quantity typed in before doAjaxControls() is done will be cleared: this strange behaviour is fortunately not present with JBoss EAP 6.0.1.GA (AS 7.1.3.Final-redhat-4, jboss-jsf-api_2.1_spec-2.0.7.Final-redhat-1).
Do you know if/how could I improve my solution?
Thanks in advance for helping!

Resources