I have a rich:dataTable and like to show details to each row in a rich:popupPanel when the user clicks on the detail button.
I do this like this
<h:panelGrid columns="3" columnClasses="titleCell">
<h:form id="form">
<rich:dataScroller for="table" maxPages="5" />
<rich:dataTable value="#{tournSelectionBean.tournaments}"
var="tourn" id="table" rows="10">
<rich:column>
<f:facet name="header">
<h:outputText value="Name" />
</f:facet>
<h:outputText value="#{tourn.name}" />
</rich:column>
<rich:column>
<a4j:commandButton value="Detail"
action="#{tournSelectionBean.setCurrentTournament(tourn)}"
render=":detailpopup"
oncomplete="#{rich:component('detailpopup')}.show();" />
</rich:column>
</rich:dataTable>
<rich:dataScroller for="table" maxPages="5" />
</h:form>
</h:panelGrid>
<rich:popupPanel id="detailpopup" modal="true" resizeable="false"
autosized="true">
<f:facet name="header">
<h:outputText value="#{tournSelectionBean.currentTournament.name}" />
</f:facet>
<f:facet name="controls">
<h:outputLink value="#"
onclick="#{rich:component('detailpopup')}.hide(); return false;">
</h:outputLink>
</f:facet>
<h:panelGrid columns="2" columnClasses="titleCell">
<h:outputLabel value="City" />
<h:outputLabel
value="#{tournSelectionBean.currentTournament.city}" />
</h:panelGrid>
Close
</rich:popupPanel>
The setPropertyActionListener sets the ID correctly and the popup opens as expected. But the popup shows the details of the tournament that was in the bean when the view was created (and not the one that was set by the propertyactionlistner).
How can I achieve this?
EDIT: Updated above code and added Bean:
#Named("tournSelectionBean")
#ViewScoped
public class TournamentSelectionBean implements Serializable {
#EJB
private TournamentControllerInterface tournamentController;
private List<Tournament> tournaments;
private Tournament currentTournament;
#PostConstruct
public void init() {
tournaments = tournamentController.loadTournaments(true, false);
}
/**
* #return the tournaments
*/
public List<Tournament> getTournaments() {
return tournaments;
}
/**
* #param tournaments
* the tournaments to set
*/
public void setTournaments(List<Tournament> tournaments) {
this.tournaments = tournaments;
}
/**
* #return the currentTournament
*/
public Tournament getCurrentTournament() {
return currentTournament;
}
/**
* #param currentTournament the currentTournament to set
*/
public void setCurrentTournament(Tournament currentTournament) {
this.currentTournament = currentTournament;
}
}
You need to tell JSF to re-render the popup html before you open it:
<a4j:commandButton value="Detail"
action="#{tournSelectionBean.setCurrentTournament(tourn)}"
render=":detailpopup"
oncomplete="#{rich:component('detailpopup')}.show();" />
Be careful: if you have a <h:form> inside the popupPanel, you may have issues when you re-render the complete popup. Put everything in a <h:panelGroup> inside the form, then re-render that one.
Related
I am developing a system that the user choose some checkboxes and each checkbox have a currency value, and I want to change a outputText according to selected checkboxes.
Example: I have three checkboxes, each one have $10.00. If the user choose just two checkboxes, the outputText must show $20.00. If the user choose the last one, the outputText must show $30.00. And all this without reloading the page.
My code so far:
<h:form id="form">
<p:fieldset legend="Tipo base do site:" style="margin-bottom:20px">
<h:panelGrid columns="2" cellpadding="5">
<p:dataList value="#{tiposIndexView.tipos}" var="tipo"
type="ordered" >
R$
<h:outputText value="#{tipo.preco}" >
<f:convertNumber pattern="#0.00" />
</h:outputText>
</p:dataList>
<p:selectOneRadio id="tipo" value="#{tiposIndexView.tipos}"
layout="grid" columns="1">
<f:selectItems value="#{tiposIndexView.tipos}" var="tipo"
itemLabel="#{tipo.nome}" itemValue="#{tipo.nome}" />
</p:selectOneRadio>
</h:panelGrid>
</p:fieldset>
<p:fieldset legend="Sistemas adicionais:" style="margin-bottom:20px">
<h:panelGrid columns="2" cellpadding="5">
<p:dataList value="#{sistemasIndexView.sistemas}" var="sistema"
type="ordered" >
R$
<h:outputText value="#{sistema.preco}" >
<f:convertNumber pattern="#0.00" />
</h:outputText>
</p:dataList>
<p:selectManyCheckbox style="margin-top:0px;!important" id="grid" value="#{sistemasIndexView.sistemas}" layout="grid" columns="1">
<f:selectItems value="#{sistemasIndexView.sistemas}" var="sistema" itemLabel="#{sistema.nome}" itemValue="#{sistema}" />
</p:selectManyCheckbox>
</h:panelGrid>
</p:fieldset>
<p:fieldset legend="Valor total:">
<h:outputText>
R$
<f:convertNumber pattern="#0.00" />
</h:outputText>
</p:fieldset>
</h:form>
The last outputText is where I want to show the total value.
And one more question, every time that I open my site, all checkboxes starts checked and I want to all start unchecked. The code of checkboxes:
#ManagedBean
#ViewScoped
public class SistemasIndexView implements Serializable{
private static final long serialVersionUID = -2697991732915561009L;
private List<Sistema> sistemas;
#PostConstruct
public void init(){
sistemas = new ArrayList<>();
sistemas.add(new Sistema("Teste", 200));
sistemas.add(new Sistema("Exemplo", 300));
sistemas.add(new Sistema("gsdfaf", 50));
}
public List<Sistema> getSistemas() {
return sistemas;
}
public void setSistemas(List<Sistema> sistemas) {
this.sistemas = sistemas;
}
}
You need 2 lists, one for storing all checkboxes and second for selected ones. That's why you have all checkboxes selected because your selected values are the same as all possible.
Css mistake: style="margin-top:0px;!important" should be style="margin-top:0px !important;"
Things you need in your backing bean (with getters/setters):
List for selected items private List<Sistema> selectedSistemas;
Field for calculated sum private int sum
Method for calculating output public void calculateSum()
Code
<p:selectManyCheckbox style="margin-top:0px !important;" id="grid" value="#{sistemasIndexView.selectedSistemas}" layout="grid" columns="1">
<f:selectItems value="#{sistemasIndexView.sistemas}" var="sistema" itemLabel="#{sistema.nome}" itemValue="#{sistema}" />
<p:ajax process="#this" listener="#{test.calculateSum}" update="sum"/>
</p:selectManyCheckbox>
<h:outputText id="sum" value="#{test.sum}">
<f:convertNumber pattern="#0.00" />
</h:outputText>
And calculating method, you can change it but from what you have written it does the job
public void calculateSum() {
sum = selectedSistemas.size() * 10;
}
I am Creating a jsf application and I need to perform CRUD. So far I have managed to delete,create,and read but am unable to update the record.So my problem is, I want when the user click the update button a dialog box to pop with the details of the selected row and update the details. Here is My sample code.
<p:panelGrid columns="2">
<h:outputLabel value="Account Id"/>
<h:inputText value="#{accCtr.acc.accountNum}" />
<h:outputLabel value="Account Bal"/>
<h:inputText value="#{accCtr.acc.balance}"/>
<h:outputLabel />
<p:commandButton action="#{accCtr.create()}" value="Enter" update="dt"/>
</p:panelGrid>
<p:dataTable value="#{accCtr.list}" var="i" id="dt" style="width: 40%;" rowStyleClass="height" rowKey="#{accCtr.acc.accountNum}" >
<p:column>
<f:facet name="header">Account Num</f:facet>
#{i.accountNum}
</p:column>
<p:column>
<f:facet name="header">Account Balance</f:facet>
#{i.balance}
</p:column>
<p:column>
<f:facet name="header">Action</f:facet>
<p:commandButton value="Remove" styleClass="height"
action="#{accCtr.removeAccount(i)}"
/>
<p:commandButton value="Edit" styleClass="height"
onclick="pop.show()"
action="#{accCtr.edit(i)}"
>
</p:commandButton>
</p:column>
</p:dataTable>
</h:form>
<p:dialog widgetVar="pop" header="Account Edit">
<h:form>
<p:panelGrid columns="2">
<h:outputLabel value="Account Balance"/>
<h:inputText value="#{accCtr.acc.balance}"/>
<h:outputLabel/>
<p:commandButton value="Update"/>
</p:panelGrid>
</h:form>
</p:dialog>
can someone help me.
and my backing bean.
#ManagedBean(name="accCtr")
#SessionScoped
public class AccountController {
List<AccountTable> list=new ArrayList<>();
public AccountController() {
}
private Account_dao getDao()
{
return new Account_dao();
}
public List<AccountTable> getList() {
return getDao().findAll();
}
public void setList(List<AccountTable> list) {
this.list = list;
}
public void removeAccount(AccountTable acc) {
getDao().remove(acc);
}
public AccountTable acc=new AccountTable();
public AccountTable getAcc() {
return acc;
}
public void setAcc(AccountTable acc) {
this.acc = acc;
}
public void edit(AccountTable acc) {
setAcc(acc);
}
public String create()
{
this.acc.setUserid(10);
getDao().create(this.acc);
return "index";
}
Change your
<p:commandButton value="Edit" styleClass="height"
onclick="pop.show()"
action="#{accCtr.edit(i)}"
/>
to
<p:commandButton value="Edit" styleClass="height"
oncomplete="pop.show()"
actionListener="#{accCtr.edit(i)}"
process="#this" update=":your_dialog_form_id"
/>
A few things: In general the action atributte is used for navigation (redirect to another page for instance). Also is better to use oncomplete beacuse it gets executed when your ajax request is completed, instead of onclick that fires the action (open the dialog in your case) in the moment when you press the button, skipping validation and such things.
If your problem was, refreshing the dialog content, with the update/process (ajax) mechanism, will be updated with your current selection if you do like the second snippet.
I'm using PrimeFaces 4.0 and Netbeans 6.9.1. I followed primefaces demo here:
DataTable Single Selection
Everything working fine expect button view. Here is my code:
Customer_list.xhtml
<p:growl id="msgs" showDetail="true" />
<h:form id="formTable">
<p:dataTable styleClass="table" id="customers" var="customer" value="#{customerBean.customer}">
<p:column>
<f:facet name="header">First Name</f:facet>
#{customer.firstName}
</p:column>
<p:column>
<f:facet name="header">Last Name</f:facet>
#{customer.lastName}
</p:column>
<p:column>
<f:facet name="header">Email</f:facet>
#{customer.email}
</p:column>
<p:column>
<f:facet name="header">DOB</f:facet>
#{customer.dob}
</p:column>
<p:column style="width:4%">
<p:commandButton id="selectButton" update=":formCreate" oncomplete="dialogCustomerCreate.show()" icon="ui-icon-search" title="Update">
<f:setPropertyActionListener value="#{customer}" target="#{customerBean.selectedCustomer}" />
</p:commandButton>
</p:column>
</p:dataTable>
</h:form>
<h:form id="formCreate">
<p:dialog header="Create New Customer" widgetVar="dialogCustomerCreate" resizable="false" id="dlgCustomerCreate"
showEffect="fade" hideEffect="explode" modal="true">
<h:panelGrid id="display" columns="2" cellpadding="4" style="margin:0 auto;">
<h:outputText value="First Name:" />
<h:outputText value="#{customerBean.selectedCustomer.firstName}" style="font-weight:bold"/>
<h:outputText value="Last Name:" />
<h:outputText value="#{customerBean.selectedCustomer.lastName}" style="font-weight:bold"/>
<h:outputText value="Email:" />
<h:outputText value="#{customerBean.selectedCustomer.email}" style="font-weight:bold"/>
<h:outputText value="DOB:" />
<h:outputText value="#{customerBean.selectedCustomer.dob}" style="font-weight:bold"/>
</h:panelGrid>
</p:dialog>
</h:form>
customerBean.java
public class customerBean {
private List<Customer> customer;
private Customer selectedCustomer;
/** Creates a new instance of customerBean */
public customerBean() {
customer = new ArrayList<Customer>();
}
public List<Customer> getCustomer() {
CustomersDao cust_dao = new CustomersDao();
customer = cust_dao.findAll();
return customer;
}
public Customer getSelectedCustomer() {
return selectedCustomer;
}
public void setSelectedCustomer(Customer selectedCustomer) {
this.selectedCustomer = selectedCustomer;
}
}
CustomersDao.java
public class CustomersDao {
public List<Customer> findAll(){
List<Customer> list_cust = null;
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
String sql = "FROM Customer";
try{
session.beginTransaction();
list_cust = session.createQuery(sql).list();
session.beginTransaction().commit();
}catch(Exception e){
session.beginTransaction().rollback();
}
return list_cust;
}
}
Hope anyone suggest me what wrong in my code. It takes me 2 days to solve it. Thanks for reading!
You need to have a converter for your Customer class:
#FacesConverter(forClass = Customer.class)
public class CustomerConverter implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value != null && !value.equals("") && !value.equals("0")) {
//find and return object from DAO
} else {
return null;
}
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
//return object id as string
}
}
1) Try removing your <h:form/>, since you're not submitting any information in that dialog;
2) Try to change your <p:commandButton update=""/> to update=":display";
3) Add process="#form" to your <p:commandButton/>;
4) If that works, i don't think you need that <h:form/>.
you did not mention the correct id for displaying popup dialog at commandButton attribute update.
<p:commandButton id="selectButton" update=":formCreate:display" oncomplete="dialogCustomerCreate.show()" icon="ui-icon-search" title="Update">
<f:setPropertyActionListener value="#{customer}" target="#{customerBean.selectedCustomer}" />
</p:commandButton>
I am designing a web page in which there is a rich:DataTable which I am using to add new customer information in the Database .
So each time a click the "Add New" button, a new row should appear in the rich datatable with Blank Input Text Fields .
Problem : Even how many times I am clicking the "Add New" Button, there remains only one row in table .
Following is the code of my web page :
<a4j:outputPanel id="rep" rendered="#{adminBean.currentItem == 'Participant' || adminBean.currentItem == 'Administrator'}">
<rich:panel rendered="#{not empty adminBean.currentItem}" header="Add Customer" id="out">
<h:panelGrid columns="2">
<h:commandButton value="Add New" type="button" style="width: 70px" actionListener="#{adminBean.addCustAction}">
<a4j:ajax render="out"/>
</h:commandButton>
<a4j:commandButton value="Delete" style="margin-left: 10px; width: 70px"></a4j:commandButton>
</h:panelGrid>
<rich:dataScroller for="setcust" style="margin-top: 17px"></rich:dataScroller>
<rich:dataTable id="setcust" value="#{adminBean.customerList}" var="custl" rows="10" style="width: 900px;margin-top: 5px">
<rich:column id="col1">
<f:facet name="header">
<h:outputText value="Customer ID" style="font-size: smaller; font-weight: bolder; "/>
</f:facet>
<h:inputText value="#{custl.Id}"></h:inputText>
</rich:column>
<rich:column id="col2">
<f:facet name="header">
<h:outputText value="First Name" style="font-size: smaller; font-weight: bolder;"/>
</f:facet>
<h:inputText value="#{custl.FirstName}"></h:inputText>
</rich:column>
<rich:column id="col3">
<f:facet name="header">
<h:outputText value="Last Name" style="font-size: smaller; font-weight: bolder;"/>
</f:facet>
<h:inputText value="#{custl.lastName}"></h:inputText>
</rich:column>
<rich:column id="col4">
<f:facet name="header">
<h:outputText value="Phone" style="font-size: smaller; font-weight: bolder;"/>
</f:facet>
<h:inputText value="#{custl.phoneNo}"></h:inputText>
</rich:column>
<rich:column id="col5">
<f:facet name="header">
<h:outputText value="Address" style="font-size: smaller; font-weight: bolder;"/>
</f:facet>
<h:inputText value="#{custl.address}"></h:inputText>
</rich:column>
<rich:column id="col6">
<f:facet name="header">
<h:outputText value="City" style="font-size: smaller; font-weight: bolder;"/>
</f:facet>
<h:inputText value="#{custl.city}"></h:inputText>
</rich:column>
<rich:column id="col7">
<f:facet name="header">
<h:outputText value="Email" style="font-size: smaller; font-weight: bolder;"/>
</f:facet>
<h:inputText value="#{custl.email}"></h:inputText>
</rich:column>
</rich:dataTable>
</rich:panel>
</a4j:outputPanel>
Following is the code of the AdminBean:
#ManagedBean
#ViewScoped
public class AdminBean {
private String currentType;
private String currentItem;
private List<Customer> customerList = new ArrayList<Customer>();
private List<Account> accountList;
private List optionList;
public List getOptionList() {
optionList = new ArrayList<String>();
if (currentType.equals("Add New User")) {
optionList.add("Participant");
optionList.add("Administrator");
} else if (currentType.equalsIgnoreCase("Manage Balance")) {
optionList.add("Withdrawl");
optionList.add("Deposit");
}
return optionList;
}
public void setOptionList(List optionList) {
this.optionList = optionList;
}
public List<Account> getAccountList() {
return accountList;
}
public void setAccountList(List<Account> accountList) {
this.accountList = accountList;
}
public List<Customer> getCustomerList() {
System.out.println("got list..................");
return customerList;
}
public void setCustomerList(List<Customer> customerList) {
this.customerList = customerList;
}
public String getCurrentItem() {
return currentItem;
}
public void setCurrentItem(String currentItem) {
this.currentItem = currentItem;
}
public String getCurrentType() {
return currentType;
}
public void setCurrentType(String currentType) {
this.currentType = currentType;
}
public void addCustAction(){
System.out.println("kshitij jain.......actionListener"+customerList.size());
Customer cust = new Customer();
customerList.add(cust);
}
}
You have some problems in your code:
Every UICommand should be wrapped inside a <h:form> in order to work. Please refer to commandButton/commandLink/ajax action/listener method not invoked or input value not updated, section 1.
You're not declaring the actionListener method in the right way, the method needs an ActionEvent event parameter. It looks like you wanted to use action instead. Refer to Differences between action and actionListener for more info.
In RichFaces 4, there's no need to use <h:commandButon> together with <a4j:ajax>, this is the purpose of <a4j:commandButton>. From the documentation:
The component is similar to the JavaServer Faces (JSF) component, but additionally includes Ajax support.
Tying all these advices together, your JSF code should be (I've omitted not necessary code to test the results like styles and rendered conditions)
<a4j:outputPanel id="rep" >
<rich:panel id="out">
<h:form id="frmCustomerData">
<h:panelGrid columns="2">
<a4j:commandButton value="Add New"
action="#{adminBean.addCustAction}"
render="setcust" />
<a4j:commandButton value="Delete" />
</h:panelGrid>
<rich:dataScroller for="setcust" style="margin-top: 17px"></rich:dataScroller>
<rich:dataTable id="setcust" value="adminBean.customerList" var="custl" rows="10" style="width: 900px;margin-top: 5px">
<!-- datatable content... -->
</rich:dataTable>
</h:form>
</rich:panel>
</a4j:outputPanel>
There's no need to make any change on the managed bean.
I have a page-scoped component, which has an instance variable List with data, which I display in a datatable. This datatable has pagination, sorting and filtering.
The first time gate into the page, I get this appended in my URL: ?conversationId=97. The page works correctly, and when I change datatable pages no now component is created.
After a minute or two, and at seamingly random time, I get an exception saying that there is no context. I have not used #Create in my code or my navigation files.
So, I have two questions:
Why do I get this suffix in my URL? Why did a conversation start?
Why the exception? The component is scoped to PAGE. If I received an exception, it should not be related to a conversation. Right? Or is the conversation the exception is referring a temporary conversation?
Cheers!
UPDATE I:
The project is an Ear.
This is the page:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
<body>
<ui:composition template="/WEB-INF/facelets/templates/template.xhtml">
<ui:define name="content">
<!-- This method returns focus on the filter -->
<script type="text/javascript">
function submitByEnter(event){
if (event.keyCode == 13) {
if (event.preventDefault) {
// Firefox
event.preventDefault();
} else {
// IE
event.returnValue = false;
}
document.getElementById("refreshButton").click();
}
}
</script>
<h:form prependId="false">
<h:commandButton action="Back" value="Back to home page" />
<br />
<p><h:outputText
value="Applicants and Products (experimentation page)"
class="page_title" /></p>
<h:commandButton
action="#{applicantProductListBean.showCreateApplicant}"
value="Create Applicant" id="createApplicantButton">
</h:commandButton>
<a4j:commandButton value="Refresh" id="refreshButton"
action="#{applicantProductListBean.refreshData}"
image="/images/icons/refresh48x48.gif"
reRender="compositeTable, compositeScroller">
<!-- <f:setPropertyActionListener-->
<!-- target="# {pageScrollerBean.applicantProductListPage}" value="1" />-->
</a4j:commandButton>
<rich:toolTip for="createApplicantButton" value="Create Applicant" />
<rich:dataTable styleClass="composite2DataTable" id="compositeTable"
rows="1" columnClasses="col"
value="#{applicantProductListBean.dataModel}" var="pageAppList">
<f:facet name="header">
<rich:columnGroup>
<rich:column colspan="3">
<h:outputText styleClass="headerText" value="Applicants" />
</rich:column>
<rich:column colspan="3">
<h:outputText styleClass="headerText" value="Products" />
</rich:column>
<rich:column breakBefore="true">
<h:outputText styleClass="headerText" value="Applicant Name" />
<a4j:commandButton id="sortingApplicantNameButton"
action="#{applicantProductListBean.toggleSorting('applicantName')}"
image="/images/icons/sorting/#{sortingFilteringBean.applicantProductListSorting.sortingValues['applicantName']}.gif"
reRender="sortingApplicantNameButton, sortingApplicantEmailButton, compositeTable, compositeScroller">
<!-- <f:setPropertyActionListener-->
<!-- target="#{pageScrollerBean.applicantProductListPage}" value="1" />-->
</a4j:commandButton>
<br />
<h:inputText
value="#{sortingFilteringBean.applicantProductListFiltering.filteringValues['applicantName']}"
id="applicantNameFilterValue"
onkeypress="return submitByEnter(event)">
</h:inputText>
</rich:column>
<rich:column>
<h:outputText styleClass="headerText" value="Applicant Email" />
<a4j:commandButton id="sortingApplicantEmailButton"
action="#{applicantProductListBean.toggleSorting('applicantEmail')}"
image="/images/icons/sorting/#{sortingFilteringBean.applicantProductListSorting.sortingValues['applicantEmail']}.gif"
reRender="sortingApplicantNameButton, sortingApplicantEmailButton, compositeTable, compositeScroller">
<!-- <f:setPropertyActionListener-->
<!-- target="#{pageScrollerBean.applicantProductListPage}" value="1" />-->
</a4j:commandButton>
<br />
<h:inputText
value="#{sortingFilteringBean.applicantProductListFiltering.filteringValues['applicantEmail']}"
id="applicantEmailFilterValue"
onkeypress="return submitByEnter(event)">
</h:inputText>
</rich:column>
<rich:column>
<h:outputText styleClass="headerText" value="Applicant Actions" />
</rich:column>
<rich:column>
<h:outputText styleClass="headerText" value="Product Name" />
<a4j:commandButton id="sortingProductNameButton"
action="#{applicantProductListBean.toggleSorting('productName')}"
immediate="true"
image="/images/icons/sorting/#{sortingFilteringBean.applicantProductListSorting.sortingValues['productName']}.gif"
reRender="sortingProductNameButton, compositeTable, compositeScroller">
</a4j:commandButton>
<br />
<h:inputText
value="#{sortingFilteringBean.applicantProductListFiltering.filteringValues['productName']}"
id="productNameFilterValue"
onkeypress="return submitByEnter(event)">
</h:inputText>
</rich:column>
<rich:column>
<h:outputText styleClass="headerText" value="Product Email" />
<br />
<h:inputText
value="#{sortingFilteringBean.applicantProductListFiltering.filteringValues['productEmail']}"
id="productEmailFilterValue"
onkeypress="return submitByEnter(event)">
</h:inputText>
</rich:column>
<rich:column>
<h:outputText styleClass="headerText" value="Product Actions" />
</rich:column>
</rich:columnGroup>
</f:facet>
<rich:subTable rowClasses="odd_applicant_row, even_applicant_row"
value="#{pageAppList}" var="app">
<rich:column
styleClass=" internal_cell
composite2TextContainingColumn"
valign="top">
<h:outputText value="#{app.name}" />
</rich:column>
<rich:column
styleClass="internal_cell composite2TextContainingColumn"
valign="top">
<h:outputText value="#{app.receiptEmail}" />
</rich:column>
<rich:column valign="top" styleClass="buttonsColumn">
<h:commandButton
action="#{applicantProductListBean.showUpdateApplicant(app)}"
image="/images/icons/edit.jpg">
</h:commandButton>
<!-- <rich:toolTip for="editApplicantButton" value="Edit Applicant" />-->
<h:commandButton
action="#{applicantProductListBean.showDeleteApplicant(app)}"
image="/images/icons/delete.png">
</h:commandButton>
<!-- <rich:toolTip for="deleteApplicantButton" value="Delete Applicant" />-->
</rich:column>
<rich:column colspan="3">
<table class="productsTableTable">
<tbody>
<tr>
<td class="createProductButtonTableCell"><h:commandButton
action="#{applicantProductListBean.showCreateProduct(app)}"
value="Create Product">
</h:commandButton>
<!-- <rich:toolTip for="createProductButton" value="Create Product" />-->
</td>
</tr>
<tr>
<td><rich:dataTable value="#{app.products}" var="prod"
rowClasses="odd_product_row, even_product_row">
<rich:column
styleClass="internal_cell composite2TextContainingColumn">
<h:outputText value="#{prod.inventedName}" />
</rich:column>
<rich:column
styleClass="internal_cell composite2TextContainingColumn">
<h:outputText value="#{prod.receiptEmail}" />
</rich:column>
<rich:column styleClass="buttonsColumn">
<h:commandButton
action="#{applicantProductListBean.showUpdateProduct(prod)}"
image="/images/icons/edit.jpg">
</h:commandButton>
<!-- <rich:toolTip for="editProductButton" value="Edit Product" />-->
<h:commandButton
action="#{applicantProductListBean.showDeleteProduct(prod)}"
image="/images/icons/delete.png">
<f:setPropertyActionListener target="#{productBean.product}"
value="#{prod}" />
</h:commandButton>
<!-- <rich:toolTip for="deleteProductButton" value="Delete Product" />-->
</rich:column>
</rich:dataTable></td>
</tr>
</tbody>
</table>
</rich:column>
</rich:subTable>
<f:facet name="footer">
<h:panelGrid columns="1" styleClass="applicantProductListFooter">
<h:outputText value="#{msgs.no_results}" rendered="#{(empty applicantProductListBean.dataModel) || (applicantProductListBean.dataModel.rowCount==0)}"/>
<rich:datascroller align="center" for="compositeTable"
page="#{pageScrollerBean.applicantProductListPage}"
id="compositeScroller" reRender="compositeTable"
renderIfSinglePage="false" fastControls="hide">
<f:facet name="first">
<h:outputText value="#{msgs.first}" styleClass="scrollerCell" />
</f:facet>
<f:facet name="first_disabled">
<h:outputText value="#{msgs.first}" styleClass="scrollerCell" />
</f:facet>
<f:facet name="last">
<h:outputText value="#{msgs.last}" styleClass="scrollerCell" />
</f:facet>
<f:facet name="last_disabled">
<h:outputText value="#{msgs.last}" styleClass="scrollerCell" />
</f:facet>
<f:facet name="next">
<h:outputText value="#{msgs.next}" styleClass="scrollerCell" />
</f:facet>
<f:facet name="next_disabled">
<h:outputText value="#{msgs.next}" styleClass="scrollerCell" />
</f:facet>
<f:facet name="previous">
<h:outputText value="#{msgs.previous}" styleClass="scrollerCell" />
</f:facet>
<f:facet name="previous_disabled">
<h:outputText value="#{msgs.previous}" styleClass="scrollerCell" />
</f:facet>
</rich:datascroller>
</h:panelGrid>
</f:facet>
</rich:dataTable>
</h:form>
</ui:define>
This is the backing bean:
#Name("applicantProductListBean")
#Scope(ScopeType.PAGE)
public class ApplicantProductListBean extends
BasePagedSortableFilterableListBean {
/**
* Public field for ad-hoc injection to work.
*/
#EJB(name = "FacadeService")
public ApplicantFacadeService applicantFacadeService;
#Logger
private static Log logger;
private final int pageSize = 10;
#Out(scope = ScopeType.CONVERSATION, required = false)
Applicant currentApplicant;
#Out(scope = ScopeType.CONVERSATION, required = false)
Product product;
#Create
public void onCreate() {
System.out.println("Create");
}
#Override
protected DataModel initDataModel(int pageSize) {
// get filtering and sorting from session
sorting = getSorting();
filtering = getFiltering();
// System.out.println("Initializing a Composite3DataModel");
// System.out.println("Pagesize: " + pageSize);
// System.out.println("Filtering: " + filtering.getFilteringValues());
// System.out.println("Sorting: " + sorting.getSortingValues());
return new Composite3DataModel(1, sorting, filtering);
}
// Navigation methods
/**
* Navigation-returning method, returns the action to follow after pressing
* the "Create Applicant" button
*
* #return the action to be taken
*/
public Navigation.ApplicantProductList showCreateApplicant() {
return Navigation.ApplicantProductList.SHOW_CREATE_APPLICANT;
}
/**
* Navigation-returning method, returns the action to follow after pressing
* the "Edit Applicant" button
*
* #return the action to be taken
*/
public Navigation.ApplicantProductList showUpdateApplicant(
Applicant applicant) {
this.currentApplicant = applicant;
return Navigation.ApplicantProductList.SHOW_UPDATE_APPLICANT;
}
/**
* Navigation-returning method, returns the action to follow after pressing
* the "Delete Applicant" button
*
* #return the action to be taken
*/
public Navigation.ApplicantProductList showDeleteApplicant(
Applicant applicant) {
this.currentApplicant = applicant;
return Navigation.ApplicantProductList.SHOW_DELETE_APPLICANT;
}
/**
* Navigation-returning method, returns the action to follow after pressing
* the "Create Product" button
*
* #return the action to be taken
*/
public Navigation.ApplicantProductList showCreateProduct(Applicant app) {
this.product = new Product();
this.product.setApplicant(app);
return Navigation.ApplicantProductList.SHOW_CREATE_PRODUCT;
}
/**
* Navigation-returning method, returns the action to follow after pressing
* the "Edit Product" button
*
* #return the action to be taken
*/
public Navigation.ApplicantProductList showUpdateProduct(Product prod) {
this.product = prod;
return Navigation.ApplicantProductList.SHOW_UPDATE_PRODUCT;
}
/**
* Navigation-returning method, returns the action to follow after pressing
* the "Delete Product" button
*
* #return the action to be taken
*/
public Navigation.ApplicantProductList showDeleteProduct(Product prod) {
this.product = prod;
return Navigation.ApplicantProductList.SHOW_DELETE_PRODUCT;
}
/**
* */
#Override
public Sorting getSorting() {
if (sorting == null) {
return (getSortingFilteringBeanFromSession()
.getApplicantProductListSorting());
}
return sorting;
}
/**
*
*/
#Override
public void setSorting(Sorting sorting) {
getSortingFilteringBeanFromSession().setApplicantProductListSorting(
sorting);
}
/**
*
*/
#Override
public Filtering getFiltering() {
if (filtering == null) {
return (getSortingFilteringBeanFromSession()
.getApplicantProductListFiltering());
}
return filtering;
}
/**
*
*/
#Override
public void setFiltering(Filtering filtering) {
getSortingFilteringBeanFromSession().setApplicantProductListFiltering(
filtering);
}
/**
* #return the currentApplicant
*/
public Applicant getCurrentApplicant() {
return currentApplicant;
}
/**
* #param currentApplicant
* the currentApplicant to set
*/
public void setCurrentApplicant(Applicant applicant) {
this.currentApplicant = applicant;
}
/**
* The model for this page
*
*/
private class Composite3DataModel extends
PagedSortableFilterableDataModel<List<Applicant>> {
public Composite3DataModel(int pageSize, Sorting sorting,
Filtering filtering) {
super(pageSize, sorting, filtering);
}
#Override
protected DataPage<List<Applicant>> fetchPage(int fakeStartRow,
int fakePageSize) {
// if (logger.isTraceEnabled()) {
System.out.println("Getting page with fakeStartRow: " + fakeStartRow
+ " and fakePageSize " + fakePageSize);
// }
// to find the page size multiply the startRow and the fakePageSize
// (which is 1) to the actual page size
int startRow = fakeStartRow
* ApplicantProductListBean.this.pageSize;
int pageSize = fakePageSize
* ApplicantProductListBean.this.pageSize;
// if (logger.isTraceEnabled()) {
System.out.println("Getting page with startRow: " + startRow
+ " and pageSize " + pageSize);
// }
List<Applicant> pageApplicants = applicantFacadeService
.findPagedWithCriteria(startRow, pageSize, filtering,
sorting);
// List<Applicant> pageApplicants = applicantFacadeService
// .findPagedWithDynamicQuery(startRow, pageSize, filtering,
// sorting, true);
// if (logger.isTraceEnabled()) {
System.out.println("Set of applicants: " + pageApplicants.size());
// }
List<List<Applicant>> pageApplicantsListContainer = new ArrayList<List<Applicant>>();
pageApplicantsListContainer.add(pageApplicants);
DataPage<List<Applicant>> dataPage = new DataPage<List<Applicant>>(
this.getRowCount(), fakeStartRow,
pageApplicantsListContainer);
return dataPage;
}
#Override
protected int getDatasetSize() {
// int size = getServiceFacade().countWithCriteria(filtering,
// sorting);
// int size =
// applicantFacadeService.countWithDynamicQuery(filtering, sorting,
// false);
int size = (int) Math.ceil((double) applicantFacadeService
.countWithCriteria(filtering, sorting, false)
/ pageSize);
if (logger.isTraceEnabled()) {
logger.trace("Got Dataset Size: " + size);
}
return size;
}
}
/**
* #return the product
*/
public Product getProduct() {
return product;
}
/**
* #param product
* the product to set
*/
public void setProduct(Product product) {
this.product = product;
}
}
And this is the page file (Notice that as long as I don't leave the page no conversation is created):
<?xml version="1.0" encoding="UTF-8"?>
<page>
<navigation>
<rule if-outcome="Back">
<redirect view-id="/index.xhtml" />
</rule>
<rule if-outcome="SHOW_CREATE_PRODUCT">
<begin-conversation join="true" />
<redirect view-id="/pages/product/createProduct.xhtml" />
</rule>
<rule if-outcome="SHOW_UPDATE_PRODUCT">
<begin-conversation join="true" />
<redirect view-id="/pages/product/editProduct.xhtml" />
</rule>
<rule if-outcome="SHOW_DELETE_PRODUCT">
<begin-conversation join="true" />
<redirect view-id="/pages/product/deleteProduct.xhtml" />
</rule>
<rule if-outcome="SHOW_CREATE_APPLICANT">
<begin-conversation join="true" />
<redirect view-id="/pages/applicant/createApplicant.xhtml" />
</rule>
<rule if-outcome="SHOW_UPDATE_APPLICANT">
<begin-conversation join="true" />
<redirect view-id="/pages/applicant/editApplicant.xhtml" />
</rule>
<rule if-outcome="SHOW_DELETE_APPLICANT">
<begin-conversation join="true" />
<redirect view-id="/pages/applicant/deleteApplicant.xhtml" />
</rule>
</navigation>
</page>
UPDATE II:
the stacktrace is here
Well, Let's see
The first time gate into the page, I get this appended in my URL: ?conversationId=97
ok. As said by Seam in Action book
Seam, by default, creates a Temporary conversation to serve the current request. A Temporary conversation is initialized immediately following restore view phase of the JSF life cycle and is destroyed after the render response phase.
And
After a minute or two, and at seamingly random time, I get an exception saying that there is no context.
Each conversation can have its own Timeout period, which defaults to the global Timeout setting
/WEB-INF/components.xml
<core:manager conversation-timeout="1000000"/>
Or page-specific
<page view-id="/app.xhtml" timeout="1000000"/>
Its value is specified in milliseconds. But it must exceed session Timeout defined in web.xml
/WEB-INF/web.xml
<!--specified in minutes-->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
Maybe it explains why you get your exception.
But if you really want to know whether you have long-running conversation, Seam stores a built-in conversation-scoped component named conversation. So inside your Managed bean, do as follows to know whether you have a long-running conversation
org.jboss.seam.core.Conversation conversation = (Conversation) Component.getInstance("conversation");
System.out.println(conversation.isLongRunning());
If you see true, someway you have started a long-running conversation. You can even see inside your page
#{conversation.longRunning}
I hope it can be useful to you.
Try making the component scoped conversation instead of page. It sounds like what you want to do is larger than page scoped, which holds the context for only a single request.
I'm not sure why you got that conversationId parameter appended to your url. However, all communication in seam happens inside of a conversation. If its page scoped, the conversation is a temporary conversation. To promote the conversation to a long running conversation, you need to a begin annotation or to start the conversation in pages.xml.
I think the seamBooking example application has some sample code that should be similar to what you are trying to do.