We use a p:dataScroller with a LazyDataModel to display products that can be dragged from lazy loaded search results and dropped into a shopping cart.
When more than one chunk of results have been loaded, we are only able to drag/drop items from the most recent chunk of data. If I try to drop an item from the first chunk into my cart, it will incorrectly drop the corresponding item from the most recently loaded chunk in stead.
Example: After the DataScroller has performed 3 lazy loads (3 chunks displayed), if I try to drop the 5th item from the first or second chunk of results, the 5th item from the 3rd chunk of results will be returned by the DragDropEvent.getData() method.
Our Facelets template looks something like this. The droppable element is the sticky header, which is a div with id = headerPanel.
<h:body>
<h:form id="form1">
<p:growl id="msgs" showDetail="true" life="2000">
<p:autoUpdate />
</p:growl>
<h:panelGroup id="headerPanel" layout="block" styleClass="header">
<ui:include src="/WEB-INF/includes/layout/Header.xhtml" />
</h:panelGroup>
<p:droppable for="headerPanel"
scope="shoppingCartAdd"
datasource="productScroller"
hoverStyleClass="dragActive"
tolerance="touch">
<p:ajax listener="#{shoppingCart.addProductToShoppingCart}"
update="shoppingCartButton shoppingCartSidebar" />
</p:droppable>
<ui:include src="/WEB-INF/includes/layout/ShoppingCartBar.xhtml" />
<h:panelGroup id="contentPanel" layout="block" styleClass="content">
<ui:insert name="contentPanel">Content</ui:insert>
</h:panelGroup>
</h:form>
</h:body>
The p:draggable elements are inside a p:dataScroller in a ui-composition that defines the contentPanel from our Facelets template:
<ui:composition template="/WEB-INF/templates/Layout.xhtml">
<ui:param name="title" value="Product Search" />
<ui:define name="contentPanel">
<p:commandButton id="submitButton"
action="#{productSearchBean.searchAction}"
ajax="false"
value="Find All Products" />
<h:panelGrid id="resultsGrid" styleClass="resultsGrid">
<p:dataScroller id="productScroller"
buffer="5"
chunkSize="10"
lazy="true"
rendered="#{productSearchBean.productList.rowCount > 0}"
rowIndexVar="resultIndex"
styleClass="scroller"
value="#{productSearchBean.productList}"
var="rowProduct">
<p:panel id="searchResultsPanel"
header="#{resultIndex + 1} - Product ##{rowProduct.productId}"
closable="true"
toggleable="true"
styleClass="searchResultsPanel">
<h:panelGrid id="productDataGrid" columns="2" columnClasses="thumbnailPanel, textPanel">
<h:panelGroup id="imageDiv" layout="block" styleClass="thumbnailContainer">
<span class="alignmentHelper" />
<p:graphicImage id="thumbnailImage" styleClass="thumbnailImage" value="#{rowProduct.thumbnailUrl}" />
<p:draggable for="thumbnailImage" helper="clone" revert="true" scope="shoppingCartAdd" />
</h:panelGroup>
<h:panelGrid id="textDataGrid" columns="2" columnClasses="padRight, padLeft">
<h:outputText value="id:" /> #{rowProduct.productId}<br/>
<h:outputText value="name:" /> #{rowProduct.productName}<br/>
</h:panelGrid>
</h:panelGrid>
</p:panel>
</p:dataScroller>
</h:panelGrid>
</ui:define>
</ui:composition>
Here's the listener method that gets invoked on a drop event. As mentioned above, the DragDropEvent.getData() method returns the wrong data item if multiple lazy loads have occurred and the user is trying to drag/drop an item from anything but the most recent chunk of data:
public void addProductToShoppingCart(DragDropEvent shoppingCartDropEvent) {
Long draggedId = productIdFromDragDrop(shoppingCartDropEvent);
if (addProductToDefaultShoppingCart(userId, draggedId)) {
fetchShoppingCartProducts();
addSuccessMessage(draggedId);
}
else {
addErrorMessage(draggedId);
}
}
private Long productIdFromDragDrop(DragDropEvent productDroppedEvent) {
Long droppedProductId = null;
Object dropObj = productDroppedEvent.getData();
if (dropObj != null && dropObj instanceof ProductView) {
ProductView view = (ProductView) dropObj;
droppedProductId = view.getProductId();
}
return droppedProductId;
}
Thanks for reading :)
Related
Initially, sorry for my English.
Well, I have dialogs in my application that work individually very well each of them, but when I need one dialog to call another, I have problems closing this second dialog opened on top of the first one. I am creating them by the java API from the primefaces. What would solve this problem?
EDIT:
Right, I call my first dialog here:
<h:outputLabel value="#{bundle.CreateProfissionalLabel_idRegraComissao}" />
<h:panelGroup>
<h:inputText readonly="true" value="#{profissionalController.selected.idRegraComissao.descricao}" id="nomeRegraComissao"/>
<p:commandButton value="#{bundle.Pesquisar}" action="#{searchRegraComissaoController.abrirDialogo()}" process="#this" update="#none">
<p:ajax event="dialogReturn" listener="#{profissionalController.regraComissaoSelecionada}" process="#this" update="nomeRegraComissao"/>
</p:commandButton>
</h:panelGroup>
My openDialog method (searchRegraComissaoController.abrirDialogo()) for the first dialog is:
public void abrirDialogo() {
Map<String, Object> opcoes = new HashMap<>();
opcoes.put("modal", true);
opcoes.put("resizable", false);
opcoes.put("contentHeight", 470);
RequestContext.getCurrentInstance().openDialog("/webapp/lovs/SearchRegraComissao", opcoes, null);
}
Now I have an xhtml file (/webapp/lovs/SearchRegraComissao.xhtml) that is rendered in this first dialog and is responsible for opening the second. Here's how it does it:
<p:outputLabel value="#{bundle.CreateRegraComissaoLabel_idClinica}" />
<p:panel>
<h:inputText readonly="true" value="#{searchRegraComissaoController.filtro.clinica.nome}" id="nomeClinica"/>
<p:commandButton value="#{bundle.Pesquisar}" actionListener="#{searchClinicaController.abrirDialogo()}" process="#this" update="#none">
<p:ajax event="dialogReturn" listener="#{searchRegraComissaoController.clinicaSelecionada}" process="#this" update="nomeClinica"/>
</p:commandButton>
</p:panel>
Right Here, it also has the method that opens this second dialog:
public void abrirDialogo() {
Map<String, Object> opcoes = new HashMap<>();
opcoes.put("modal", true);
opcoes.put("resizable", false);
opcoes.put("contentHeight", 450);
RequestContext.getCurrentInstance().openDialog("/webapp/lovs/SearchClinica", opcoes, null);
}
Well, So far, everything works fine, the problem is in the next step. Now I have the method that should close the second dialog. This method is called after the user select one row into dataTable in the second dialog:
<p:column headerText="#{bundle.Acao}">
<p:commandButton value="#{bundle.Escolher}" process="#this" action="#{searchClinicaController.selecionar(clinica)}"/>
</p:column>
And the final method is:
public void selecionar(Clinica clinica) {
clinicas = new ArrayList<>();
//todasClinicas = false;
// isCPF = "CPF";
//nome = "";
RequestContext.getCurrentInstance().closeDialog(clinica);
}
The end of this method is reached without errors but the second dialog isn't closed. Anyone can help?
SOLUTION: I was reading the guide of primefaces 6 and using primefaces 5. In primefaces 5 nested dialogs aren't supported. I just updated my version to 6 and now is working fine.
I had the same problem today with primefaces 5.2.
I solved by adding a form and config modal="true" and appendTo="#(body)"
in the second dialog.
Follows example:
main.xhtml
<h:body>
<h:form id="frmMain">
<p:commandButton value="Open"
process="#this" update="frmMain:dialog1"
oncomplete="PF('wdgDialog1').show()">
</p:commandButton>
<p:dialog id="dialog1" header="Dialog 1"
dynamic="true" modal="true"
widgetVar="wdgDialog1" >
<ui:include src="/dialog/dialog2.xhtml" />
</p:dialog>
</h:form>
</h:body>
dialog2.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<p:dialog id="dialog2" header="Dialog 2"
modal="true" appendTo="#(body)"
widgetVar="wdgDialog" >
<h:form id="frmDialog">
<p:panel>
<p:commandButton value="Test"/>
</p:panel>
</h:form>
</p:dialog>
</ui:composition>
I am using Primefaces 3.5, Jsf 2 and I have a datatable, now I implemented a dialog like the primefaces showcase(singlerowselection), it works fine, but I want to edit the row IN the dialog. Furthermore I want that the inputtext is filled with the data from the cell of the datatable, so that you can easily edit it!(like the row editor does it, just in a dialog)
Not like this: http://i.stack.imgur.com/J55j0.jpg
Watermark works, but it is no option because the text disappears if you want to edit it.
It should be like that: http://i.stack.imgur.com/cAFLo.jpg
So, can someone tell me how the cell data can be displayed and edited?
Here is the xhtml (dialog is not in the datatable):
<p:dialog id="dialog" header="Server Detail" widgetVar="serDialog"
resizable="false" showEffect="clip" hideEffect="fold" dynamic="true">
<h:panelGrid id="display" columns="3" cellpadding="4">
<h:outputText value="Data Center Location " />
<p:inputText id="datacenter" value="#{server.dataCenterLocation}"></p:inputText>
<h:outputText value="Identification " />
<h:inputText id="identification" value="#{server.identification}"></h:inputText>
<p:watermark for="identification"
value="#{serverBean.selectedServer.identification}"></p:watermark>
</h:panelGrid>
<p:growl id="growl" showDetail="true" sticky="false" />
<p:commandButton value="Edit Server" action="#{server.onEdit}" update="#form, growl" />
</p:dialog>
the method in the bean(name= server)
(without the selectedServer(name =serverBean) with the getter and setter):
public void onEdit() throws Exception {
PreparedStatement ps = null;
Connection con = null;
int i = 0;
try {
Server ser = new Server();
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver")
.newInstance();
con = DriverManager
.getConnection("jdbc:sqlserver://...");
String sql = "UPDATE VAI_Serverlist SET [Data Center Location]= ?,... WHERE Identification='"
+ ser.identification + "'";
ps = con.prepareStatement(sql);
ps.setString(1, ser.dataCenterLocation);
...
i = ps.executeUpdate();
} catch (SQLException e) {
System.out.println(i);
e.printStackTrace();
} finally {
try {
con.close();
ps.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Thanks in advance!
<h:form id="form">
<p:dataTable id="table" var="item" value="#{ManagedBean.list()}"
<f:facet name="footer">
<p:commandButton id="showUpdateButton" value="#{msgForms['actions.Edit']}"
update=":update_form"
icon="ui-icon-pencil"
style="margin: 0%"
ajax="true"
immediate="true"
oncomplete="PF('DialogUpdate').show()"
/>
</f:facet>
</p:dataTable>
<h:form id="form">
<p:dialog id="dialog_update"
modal="true"
header="${msgForms['titles.update']}"
widgetVar="DialogUpdate" resizable="false"
showEffect="clip" hideEffect="fold"
>
<h:form id="update_form">
<h:panelGrid columns="3" id="panel">
<!--FIELDS-->
<h:outputLabel for="nombre" value="#{msgForms['fields.nombre']}:" />
<p:inputText id="nombre"
value="#{ManagedBean.selectedItem.nombre}"
required="true"
requiredMessage="#{msgForms['field.required']}"
>
<p:ajax event="keyup" update="nombreMsg" global="false"/>
</p:inputText>
</h:panelGrid>
<!--/FIELDS-->
<!-- BUTTONS ACTIONS-->
<p:commandButton id="updateButtonDg"
value="#{msgForms['actions.update']}"
icon="ui-icon-pencil"
actionListener="#{ManagedBean.update()}"
update=":form:"
style="margin: 0%"
ajax="true"
onclick="DialogUpdate.hide();"
>
</p:commandButton>
<!-- /BUTTONS ACTIONS-->
</h:form>
</p:dialog>
the MANAGED BEAN..
#Named("ManagedBean")
#RequestScoped
public class ManagedBean {
//Spring Item Service is injected...
#Inject
IItemService itemService; //if not required because if you use dependencies injection to connect with de database
private List<Item> filteredItems; //only if you use the attribute: filteredValue="#{ManagedBean.filteredItems}" in the dataTable
private List<Item> items;
public void update() {
//here you save the changes in the data base
this.itemService().updateItem(this.selectedItem);
}
this is more or less what I use, I can not put the literal code, but I think I have not left anything important, so i hope it could to help you.
I recommend that you take a look at the tutorial
http://www.javacodegeeks.com/2012/04/jsf-2-primefaces-3-spring-3-hibernate-4.html
it shows how to integrate jsf2 Spring3 hibernate in your project and also how to inject dependencies using annotations, i recomend you the use of hibernate framework to interact with your database
I have a Users table. Added, view and delete work. But I have problem to edit.
My list page:
<h:form id="form">
<p:dataTable styleClass="table" value="#{userMB.allAdmins}" var="admin" paginator="true" rows="15" rowKey="#{admin.id}" selection="#{userMB.user}" selectionMode="single">
<f:facet name="header">
Lista administratorów
</f:facet>
<p:column headerText="#{msg.firstName}">
<h:outputText value="#{admin.firstName}" />
</p:column>
<p:column headerText="#{msg.lastName}">
<h:outputText value="#{admin.lastName}" />
</p:column>
<p:column headerText="#{msg.personalId}">
<h:outputText value="#{admin.personalId}" />
</p:column>
<f:facet name="footer">
<p:commandButton id="viewButton" value="#{msg.info}" icon="ui-icon-search"
update=":form:display" oncomplete="userDialog.show()"/>
<p:commandButton action="#{userMB.createStart()}" value="#{msg.add}" icon="ui-icon-plus" />
<p:commandButton action="#{userMB.editStart()}" value="#{msg.edit}" >
<f:setPropertyActionListener target="#{userMB.user}" value="#{userMB.user}" />
</p:commandButton>
<p:commandButton action="#{userMB.deleteUser()}" value="#{msg.delete}" icon="ui-icon-close"/>
</f:facet>
</p:dataTable>
<p:dialog id="dialog" header="Administrator" widgetVar="userDialog" resizable="false"
width="300" showEffect="clip" hideEffect="explode">
<h:panelGrid id="display" columns="2" cellpadding="4">
<f:facet name="header">
<p:graphicImage value="./../../images/person4.png" width="150" height="150"/>
</f:facet>
<h:outputText value="#{msg.firstName}" />
<h:outputText value="#{userMB.user.firstName}" />
<h:outputText value="#{msg.lastName}" />
<h:outputText value="#{userMB.user.lastName}" />
<h:outputText value="#{msg.personalId}" />
<h:outputText value="#{userMB.user.personalId}" />
</h:panelGrid>
</p:dialog>
</h:form>
I want to send the selected user on the next page:
I use aciontListener:
<p:commandButton action="#{userMB.editStart()}" value="#{msg.edit}" >
<f:setPropertyActionListener target="#{userMB.user}" value="#{userMB.user}" />
</p:commandButton>
My edit page where I want to send user:
<h:form>
<div id="userPanel">
<h:inputHidden value="#{userMB.user}" />
<p:panel id="panelUser" header="Edytuj administratora" >
<div id="panelImage">
<img src="./../../images/person4.png" alt="person" width="150px" height="130px"/>
</div>
<h:panelGrid columns="3">
<p:outputLabel for="firstName" value="#{msg.firstName}"></p:outputLabel>
<p:inputText id="firstName" value="#{userMB.user.firstName}" label="#{msg.firstName}" required="true">
<f:validator validatorId="nameValidator" />
<p:ajax update="msgFristName" event="keyup" />
</p:inputText>
<p:message for="firstName" id="msgFristName"/>
<p:outputLabel for="lastName" value="#{msg.lastName}"></p:outputLabel>
<p:inputText id="lastName" value="#{userMB.user.lastName}" label="#{msg.lastName}" required="true">
<f:validator validatorId="nameValidator" />
<p:ajax update="msgLastName" event="keyup" />
</p:inputText>
<p:message for="lastName" id="msgLastName"/>
<p:outputLabel for="personalId" value="#{msg.personalId}"></p:outputLabel>
<p:inputText id="personalId" value="#{userMB.user.personalId}" label="#{msg.personalId}" required="true">
<f:validator validatorId="personalIdValidator" />
<p:ajax update="msgPersonalId" event="keyup" />
</p:inputText>
<p:message for="personalId" id="msgPersonalId"/>
<p:outputLabel for="password" value="#{msg.password}"></p:outputLabel>
</p:panel>
</div>
</h:form>
I added: <h:inputHidden value="#{userMB.user}" /> but I do not see data user, only empty field. How do I send this person? I used once this method in other project, a little different without primefaces and it worked. Why now does not work?
Method editStart:
public String editStart() {
return "editStart";
}
faces-config:
<navigation-case>
<from-outcome>editStart</from-outcome>
<to-view-id>/protected/admin/adminEdit.xhtml</to-view-id>
<redirect/>
</navigation-case>
When I'm on the side adminEdit I edited the pool and do editUser method:
public String editUser() {
FacesContext context = FacesContext.getCurrentInstance();
Map requestParameterMap = (Map) context.getExternalContext().getRequestParameterMap();
try {
String userRole = requestParameterMap.get("userRole").toString();
String active = requestParameterMap.get("active").toString();
Boolean act = Boolean.parseBoolean(active);
user.setRole(userRole);
user.setActive(act);
userDao.update(user);
} catch (EJBException e) {
sendErrorMessageToUser("Edit error");
return null;
}
sendInfoMessageToUser("Account edited");
return user.getRole() + "List";
}
My method editStart use only for navigation.
You can either consider Przemek's answer or use one of the 4 ways of passing a parameter to a backing bean.
1. Method expression
2. f:param
3. f:atribute
4. f:setPropertyActionListener
For very well explained full explanation refer to this
It has easy to understand examples. Take a look and pick what fits your needs.
Or simply:
In the actual managed bean...
public String navigationButtonListener(User parameter) {
FacesContext.getCurrentInstance().getExternalContext().getRequestMap()
.put("parameterAttribute", parameter);
return "my-destination-page";
}
In the destination managed bean...
#PostConstruct
public void init(){
myAttribute= (User) FacesContext.getCurrentInstance()
.getExternalContext().getRequestMap().get("parameterAttribute");
}
Good Luck!
You can pass your userid through the session.
Add a parameter to your commandLink
<p:commandButton action="#{userMB.editStart()}" value="#{msg.edit}>
<f:param name="userId" value="#{userMB.user.id}" />
</p:commandButton>
In your backing bean do this
FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest myRequest = (HttpServletRequest)context.getExternalContext().getRequest();
HttpSession mySession = myRequest.getSession();
Integer userId = Integer.parseInt(myRequest.getParameter("userId"));
After that you can reload the user you want to edit with the Id you got
I am using Primefaces AutoComplete and I am getting records from database using Hibernate.
I am able to select values from database when I type in text. What I would like to achieve is when I select a name when I type characters, I would want my other columns in jsf page to get populated. E.g When I select employee name "SMITH" I want employee number, department to get filled with SMITH's employee number and department.
I have the following in jsf page.
<p:autoComplete value="#{myMB.selectedEmployee}"
id="basicPojo" minQueryLength="3"
completeMethod="#{myMB.complete}" var="p"
itemLabel="#{p.empName}"
converter="#{myconverter}"
forceSelection="true" >
<h:outputLabel value="Emp Number" />
<h:outputText value="#{p.employeeNumber}" />
<h:outputLabel value="Department" />
<h:outputText value="#{p.employeeDepartment}" />
</p:autoComplete>
When I select a name, other fields are not getting displayed.
What could be the reason for this? How can I achieve the desired result?
Any help is highly appreciated.
Edit 1
<p:dialog header="Create New Request" style="font-weight:bold"
widgetVar="requestNewDialog" resizable="false"
id="newDlg"
showEffect="fade" hideEffect="fade" appendToBody="true"
modal="true" position="center top" width="850" height="450">
<h:panelGrid columns="2" cellspacing="2">
<h:outputText value="New Employee No:" />
<h:outputText value="" />
</h:panelGrid>
<p:separator />
<p:panelGrid columns="6">
<h:outputLabel value="Employee # " for="emp" />
<p:autoComplete value="#
{myMB.selectedEmployee}"
id="basicPojo" minQueryLength="3"
completeMethod="#{myMB.complete}" var="p"
itemLabel="#{p.longName}"
converter="#{employeeNameConverter}"
forceSelection="true" >
<p:ajax event="itemSelect" update="num"
listener="#{myMB.handleSelect}" />
<h:outputLabel value="Name" for="name" />
<h:outputText value="#{p.employeeNumber}" />
</p:autoComplete>
<h:outputLabel id="num" value="Department" for="dept" />
<p:inputText id="dept" value="#{p.employeeNumber}" >
</p:inputText>
</p:panelGrid>
<p:separator />
</p:dialog>
ManagedBean complete Method
public List<Employee> complete(String query) {
List<Employee> suggestions;
suggestions = new ArrayList<Employee>();
try {
EmployeeQueryData q = new EmployeeQueryData ();
getService().getEmployee(q,query);
employee = q.getResult();
for (Employee p : employee) {
if (p.getEmpName().toLowerCase().contains(query));
suggestions.add(p); //
}
} catch (Exception e) {
}
return suggestions;
}
Use <p:ajax event="itemSelect"...
<p:autoComplete>...
<p:ajax event="itemSelect" update="someOtherFieldId someOtherFieldId2" />
</p:autoComplete>
I want to create h:datatable with list of data:
<h:dataTable id="dataTable" value="#{SessionsController.dataList}" binding="#{table}" var="item">
<!-- Check box -->
<h:column>
<f:facet name="header">
<h:outputText value="Select" />
</f:facet>
<h:selectBooleanCheckbox onclick="highlight(this)"
value="#{item.selected}" />
</h:column>
<h:column>
<f:facet name="header">
<h:commandLink value="№"
actionListener="#{SessionsController.sort}">
<f:attribute name="№" value="№" />
</h:commandLink>
</f:facet>
<h:outputText
value="#{table.rowIndex + SessionsController.firstRow + 1}" />
</h:column>
<h:column>
<f:facet name="header">
<h:commandLink value="Account Session ID"
actionListener="#{SessionsController.sort}">
<f:attribute name="sortField" value="Account Session ID" />
</h:commandLink>
</f:facet>
<h:outputText value="#{item.aSessionID}" />
</h:column>
<h:column>
<f:facet name="header">
<h:commandLink value="User ID"
actionListener="#{SessionsController.sort}">
<f:attribute name="sortField" value="User ID" />
</h:commandLink>
</f:facet>
<h:outputText value="#{item.userID}" />
</h:column>
<h:column>
<f:facet name="header">
<h:commandLink value="Activity Start Time"
actionListener="#{SessionsController.sort}">
<f:attribute name="sortField" value="Activity Start Time" />
</h:commandLink>
</f:facet>
<h:outputText value="#{item.activityStart}" />
</h:column>
<h:column>
<f:facet name="header">
<h:commandLink value="Activity End Time"
actionListener="#{SessionsController.sort}">
<f:attribute name="sortField" value="Activity End Time" />
</h:commandLink>
</f:facet>
<h:outputText value="#{item.activityEnd}" />
</h:column>
<h:column>
<f:facet name="header">
<h:commandLink value="Activity"
actionListener="#{SessionsController.sort}">
<f:attribute name="sortField" value="Activity" />
</h:commandLink>
</f:facet>
<h:outputText value="#{item.activity}" />
</h:column>
</h:dataTable>
I want when I click on a table row to open a new page which displays more details. I want to use the table key aSessionID which will be used for SQL query to get a data from the database. I know that I can use h:commandLink to pass the key but I don't want ugly html link. Is there other way to click on the JSF table row, pass a key and open a new window?
Best Wishes
EDIT
I found one possible solution here
Using this JavaScript code it's possible to open a new window when the user clicks on a row:
<table id="row_link">
<tbody>
<tr>
<td>link</td>
<td>info 1</td>
</tr>
<tr>
<td>link</td>
<td>info 2</td>
</tr>
</tbody>
</table>
$("table#row_link tbody tr").click(function () {
window.location = $(this).find("a:first").attr("href");
});
The question is how I can pass this key aSessionID to the new window.
In the above example href is used to pass the link to the new window. What attribute can be used in JSF table?
#BalusC (JSF expert) has a post about managing Datatable in JSF 1.2 but it works for JSF 2.x too. You're interested in the select row on click section.
UPDATE:
Let me explain the example. First, every JSF component ID will have this form: :, example:
<h:form id="myForm">
<h:inputText id="myInputText" value="#{myBean.textValue}" />
</h:form>
This will generate the HTML:
<form id="myForm">
<input type="text" id="myForm:myInputText" />
</form>
Second, you have to update the generated DOM for the datatable. He's doing that by javascript and also gives you the js code:
function addOnclickToDatatableRows() {
//gets all the generated rows in the html table
var trs = document.getElementById('form:dataTable').getElementsByTagName('tbody')[0]
.getElementsByTagName('tr');
//on every row, add onclick function (this is what you're looking for)
for (var i = 0; i < trs.length; i++) {
trs[i].onclick = new Function("highlightAndSelectRow(this)");
}
}
Third, define the highlightAndSelectRow js function (you can change the name to whatever you want).
function highlightAndSelectRow(tr) {
//get all the datatable rows
var trs = document.getElementById('form:dataTable').getElementsByTagName('tbody')[0]
.getElementsByTagName('tr');
//find the selected rowby using the tr parameter
for (var i = 0; i < trs.length; i++) {
if (trs[i] == tr) {
//once found it, change the color (maybe you don't need this part)
trs[i].bgColor = '#ff0000';
//update a hidden value in the form (maybe you need this code)
document.form.rowIndex.value = trs[i].rowIndex;
//here, you can add js code to open a new window
//or simulate a button/link click or something else you need.
} else {
trs[i].bgColor = '#ffffff';
}
}
}
UPDATE 2:
I've made a test for this case. I'll show you the code to get it done using facelets.
DataTable.xhtml
<script type="text/javascript">
function addOnclickToDatatableRows() {
//gets all the generated rows in the html table
var trs = document.getElementById('myForm:dataTable').getElementsByTagName('tbody')[0]
.getElementsByTagName('tr');
//on every row, add onclick function (this is what you're looking for)
for (var i = 0; trs.length > i; i++) {
trs[i].onclick = new Function("rowOnclick(this)");
}
}
function rowOnclick(tr) {
var elements = tr.cells[0].childNodes;
for(var i = 0; elements.length > i; i++) {
//get the link
if ((typeof elements[i].id !== "undefined") &&
(elements[i].id.indexOf("lnkHidden") > -1)) {
//open a new window/tab using the href generated in link
window.open(elements[i].href);
break;
}
}
return false;
}
</script>
<h:form id="myForm">
<h1>Show data</h1>
<h:dataTable id="dataTable" var="data" value="#{datatableBean.lstData}">
<h:column>
<f:facet name="header">
<h:outputText value="ID" />
</f:facet>
<h:outputText value="#{data.id}" />
<!-- define a hidden link for every row of the datatable
the value attribute contains the page to redirect. -->
<h:outputLink id="lnkHidden" value="AnotherPage.xhtml"
style="display:none">
<f:param name="id" value="#{data.id}" />
</h:outputLink>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Value" />
</f:facet>
<h:outputText value="#{data.value}" />
</h:column>
</h:dataTable>
</h:form>
DataTableBean class
#ManagedBean
#ViewScoped
public class DatatableBean {
private List<Data> lstData;
/**
* Creates a new instance of datatableBean
*/
public DatatableBean() {
lstData = new ArrayList<Data>();
lstData.add(new Data(1, "Hello World"));
lstData.add(new Data(2, "Hello StackOverflow"));
lstData.add(new Data(3, "Hello Luiggi"));
System.out.println("LOL");
}
//define getters and setters...
}
AnotherPage.xhtml
<h1>This is another page</h1>
<h:panelGrid columns="2">
<h:outputText value="Selected ID" />
<h:outputText value="#{anotherPageBean.id}" />
</h:panelGrid>
AnotherPageBean class
#ManagedBean
#RequestScoped
public class AnotherPageBean {
private int id;
/**
* Creates a new instance of AnotherPageBean
*/
public AnotherPageBean() {
try {
this.id = Integer.parseInt((String)FacesContext
.getCurrentInstance().getExternalContext()
.getRequestParameterMap().get("id"));
//by getting the id you can get more data
}
catch (Exception e) {
this.id = 0;
}
}