Modal edit dialog on Primefaces with JSF - ajax

I'm trying to create some CRUD JSF application with edit/new screen implemented as a modal dialog. The problem is that I can't find a way how to make new and edit operation done by this dialog performed with ajax. With delete all was very simple (just ajax="true" option).
Here is a code of button which is used to show the dialog
<h:form id="dataForm">
<div class="ui-g">
<div class="ui-g-12 ui-md-9">
<p:dataGrid var="product" value="#{products.productList}" columns="3" layout="grid"
rows="12" paginator="true" id="products"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="6,12,16">
<f:event type="preRenderView" listener="#{products.preloadProductList}" />
<f:facet name="header">
Products
</f:facet>
<p:panel header="#{product.name}" style="text-align:center">
<h:panelGrid columns="1" style="width:100%">
<h:outputText value="#{product.name}"/>
<h:outputText value="#{product.price}"/>
<%-- Here new/edit dialog window is opened --%>
<p:commandLink update=":dataForm:productDetail" oncomplete="PF('productDialog').show()">
Edit
<f:setPropertyActionListener value="#{product}" target="#{products.product}"/>
</p:commandLink>
<p:commandLink update=":dataForm" action="#{products.deleteAction(product)}" ajax="true">
Delete
</p:commandLink>
</h:panelGrid>
</p:panel>
</p:dataGrid>
<ui:include src="WEB-INF/dialogs/edit_product.xhtml"/>
</div>
</div>
</h:form>
Here is dialog window which is moved to separete file edit_product.xhtml
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<p:dialog header="Product Info" widgetVar="productDialog" modal="true" showEffect="fade"
hideEffect="fade"
resizable="false">
<p:outputPanel id="productDetail" style="text-align:center;">
<p:panelGrid columns="2" rendered="#{not empty products.product}"
columnClasses="label,value">
<h:outputText value="Id:"/>
<h:outputText value="#{products.id}"/>
<h:outputText value="Name"/>
<h:inputText value="#{products.name}"/>
<h:outputText value="Price"/>
<h:inputText value="#{products.price}"/>
</p:panelGrid>
<h:commandButton value="Save" action="#{products.saveProduct}"/>
</p:outputPanel>
</p:dialog>
</ui:composition>
Here is Managed bean which is used by the Product dataGrid and dialog window.
#ManagedBean(name = "products")
#SessionScoped
public class ProductsBean {
private static final Logger logger = LoggerFactory.getLogger(ProductsBean.class);
#Inject
private ProductRepository productRepository;
private Product product;
private Collection<Product> productList;
public void preloadProductList(ComponentSystemEvent event) throws AbortProcessingException {
productList = productRepository.getAll();
}
public String getId() {
return String.valueOf(product.getId());
}
public void setId(String id) {
product.setId(Long.valueOf(id));
}
public String getName() {
return product.getName();
}
public void setName(String name) {
product.setName(name);
}
public int getPrice() {
return product.getPrice();
}
public void setPrice(int price) {
product.setPrice(price);
}
public Product getProduct() {
return this.product;
}
public void setProduct(Product product) {
this.product = product;
}
public Collection<Product> getProductList() {
logger.info("Get product list");
return productList;
}
public void newProductAction() {
this.product = new Product();
}
public void deleteAction(Product product) {
logger.info("Delete product");
productRepository.remove(product);
}
public void saveProduct() {
productRepository.merge(product);
}
}
No matter if I add ajax option or not the whole window is reloaded after Save button is pressed. Could you show me the right direction for the implementation, please?
P.S. If you need more code to answer you can find it here:
Main page with Product table https://github.com/usharik/GeekBrainsJavaEE/blob/master/lesson5-jpa/src/main/webapp/index.xhtml
Edit/New dialog https://github.com/usharik/GeekBrainsJavaEE/blob/master/lesson5-jpa/src/main/webapp/WEB-INF/dialogs/edit_product.xhtml

Related

losing request parameter in jsf for second ajax poll call

I'm facing a problem with poll request, the first call is ok and the second is loosing the request parameter. Below is the code:
<h:form id="form">
<p:poll interval="10" listener="${emsstatbean.getEmsStat_list(request.getParameter('para'))}" update="emstatTable" />
<p:dataTable id="emstatTable" var="emsstat" value="${emsstatbean.getEmsStat_list(request.getParameter('para'))}" emptyMessage="No statistic found with given criteria" styleClass="table table-striped table-bordered table-hover" >
<p:column headerText="Server Hostname" >
<h:outputText value="#{emsstat.id.timeStamp}" />
</p:column>
<p:column headerText="Os name" >
<h:outputText value="#{emsstat.upTime}" />
</p:column>
<p:column headerText="Os name" >
<h:outputText value="${emsstat.state}" />
</p:column>
</p:dataTable>
</h:form>
and this is the bean class:
#ManagedBean(name = "emsstatbean")
public class EmsStatBean implements Serializable
{
public List<TibcoEmsStat> getEmsStat_list(int p)
{
return service.listEmsStats(p);
}
#ManagedProperty("#{emsStatService}")
EmsStatService service;
#PostConstruct
public void init()
{
}
public void setService(EmsStatService service)
{
this.service = service;
}
}
This is the URL called: content/public/TibcoEmsStat.xhtml?para=254
So when I paste that on browsers I'm getting the data table with all rows, but when I wait 10 sec I don't see content and I get "No statistic" found with given criteria, because parameter is empty.
Can you please help me to understand where is the issue?
this is how i fixed after reviewing some suggested link
added to the bean:
#ViewScoped
and a variable to store the id
public int ems_inst;
public int getEms_inst() {
return ems_inst;
}
public void setEms_inst(int ems_inst) {
this.ems_inst = ems_inst;
}
on the xhtml i did:
<f:metadata>
<f:viewParam name="ems_inst" value="#{emsstatbean.ems_inst}" />
</f:metadata>
<h:form id="form">
<p:poll interval="10"
listener="${emsstatbean.getEmsStat_list(emsstatbean.ems_inst)}" update="emstatTable" />
<p:dataTable id="emstatTable" var="emsstat" value="${emsstatbean.getEmsStat_list(emsstatbean.ems_inst)}"
all now is working fine
thanks

PF SetPropertyActionListener breaks after first time

i've a problem that's driving me crazy! I have a component which renders a panel that have links on a footer. This links have, among other things, a title and HTML content I want to show. The idea is basically that when a link is clicked, the content of the page is changed via ajax and the html content of the link is shown (The footer remains on the page). Debbuging I've noticed that the first time a link is clicked the content does change, but then it doesn't. The setPropertyActionListener of the p.commandlinks in my composite component aren't executed any more after first time. I'have debbuged the project and this seems to be the problem, but I can't figure out why
Part of my composite component. Tryed setting an onstart and oncomplete js functions on the command link, and both are executed but the actionListeners aren't.
<cc:interface>
<cc:attribute name="compId"/>
<cc:attribute name="title"/>
<cc:attribute name="bean"/>
...
</cc:interface>
<!-- IMPLEMENTATION -->
<cc:implementation>
<p:panel id="#{cc.attrs.compId}" header="#{cc.attrs.title}"
widgetVar="#{cc.attrs.compId}"
styleClass="#{cc.attrs.styleClass}">
<h:form>
<p:dataList id="datalist-#{cc.attrs.compId}" value="#{cc.attrs.bean.currentList}"
type="definition" widgetVar="datalist-#{cc.attrs.compId}"
var="items" >
<p:commandLink action="#{navBean.active}" update="#([id$=content])" styleClass="link"
value="#{items.descrInLang}" rendered="#{items.typeUrl eq 0}">
<f:setPropertyActionListener value="infoPage" target="#{navBean.selection}"/>
<f:setPropertyActionListener value="#{items.descrInLang}" target="#{infoPage.title}" />
<f:setPropertyActionListener value="#{items.HTMLContent}" target="#{infoPage.HTMLContent}"/>
</p:commandLink>
</p:dataList>
</h:form>
</p:panel>
</cc:implementation>
Part of my Navigation Bean
public void active() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException {
setAlbums(selection.equals("albums"));
setBand(selection.equals("band"));
setConcerts(selection.equals("concerts"));
setContacts(selection.equals("contacts"));
setHome(selection.equals("home"));
setSiteMap(selection.equals("siteMap"));
setInfoPage(selection.equals("infoPage"));
}
public void setSelection(String selection) {
this.selection = selection;
}
public boolean isInfoPage() {
return infoPage;
}
public void setInfoPage(boolean infoPage) {
this.infoPage = infoPage;
}
The bean which stores the title & HTML Content to show. After the first click on the link, the getters of Title & HTML content are executed, but the setters aren't (as declared in the setPropertyActionListeners)
#ManagedBean
#SessionScoped
public class InfoPage implements Serializable {
private String title;
private String HTMLContent;
public InfoPage() {
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getHTMLContent() {
return HTMLContent;
}
public void setHTMLContent(String HTMLContent) {
this.HTMLContent = HTMLContent;
}
}
The content part of the template which indicates what content should be shown according to the selected page on the NavBean. I pass the HTML content and the title of the infoPage as a parameter
<h:head>
</h:head>
<h:body>
<!-- the all containing file -->
<ui:composition template="template.xhtml">
<ui:define name="content">
<h:panelGroup layout="block" id="content">
<h:panelGroup layout="block" rendered="#{navBean.home}">
<ui:include src="homecontent.xhtml"/>
</h:panelGroup>
....
<h:panelGroup layout="block" rendered="#{navBean.infoPage}">
<ui:include src="infoPage.xhtml">
<ui:param name="title" value="#{infoPage.title}"/>
<ui:param name="infoContent" value="#{infoPage.HTMLContent}"/>
</ui:include>
</h:panelGroup>
</h:panelGroup>
</ui:define>
</ui:composition>
</h:body>
The info Page.
<h:form id="infoPageForm">
<p:panel id="infoPagePanel" header="#{title}">
<h:panelGrid columns="1" cellpadding="10">
<h:outputText escape="false" value="#{infoContent}" />
</h:panelGrid>
</p:panel>
</h:form>
Thanks for your time!

p:commandButton action not invoked after and ajax update

I have a JSF page which has a p:commandButton which has ajax=true and renders a p:panel which is wrapped in p:outputPanel when clicked. When this button is clicked the action method will set showCreateUser value in ManagedBean to true and this is used to render the Panel. This works fine - on button click the panel is rendered properly. Inside the p:panel there is another p:commandButton. This commanButton is not working as nothing happens when I click on it. The action method is never invoked. When I debug I realised that even though the ajax action sets showCreateUser to true but when I click on second button the showCreateUser value is false. So, the panel panel rendered=false and so the action is never invoked. Following are the xhtml and managedbean class. How can I resolve this? Thanks for your help!
registration.xhtml
<h:form id="userForm" style="background-color:white;border:0px; width:90%;">
<p:messages id="messagesForDebugging"
showDetail="true"
autoUpdate="true" />
<ui:debug hotkey="x"/>
<div style="margin-bottom: 10px;">
<p:commandButton id="btnConfirmYes" value="Yes" ajax="true" update="userRegOutPanel"
action="#{regBean.confirmYes}" styleClass="button" style="height:35px;">
<!-- <f:ajax render="userRegOutPanel" execute="userRegOutPanel"/> -->
</p:commandButton>
<p:commandButton id="btnConfirmNo" value="No" ajax="false"
action="#{regBean.confirmNo}" styleClass="button" style="height:35px;"/>
</div>
<p:outputPanel id="userRegOutPanel">
<p:panel id="userRegPanel" rendered="#{regBean.showCreateUser}">
<p:panelGrid id="userRegPanelGrid">
<p:row>
<p:column style="width:40%;background-color:#00a5b6;-moz-border-radius: 10px;-webkit-border-radius: 10px;-khtml-border-radius: 10px;border-radius: 10px;text-align:left;">
<h:inputHidden id="ssn" value="#{regBean.ssn}"/>
<p:panelGrid>
<p:row>
<p:column>
<p:commandButton value="Submit" ajax="true" action="#{regBean.submitRegistration}"
styleClass="button" style="width:140px;height:35px;" type="submit"/>
</p:column>
</p:row>
</p:panelGrid>
</p:column>
</p:row>
</p:panelGrid>
</p:panel>
</p:outputPanel>
</h:form>
Managed Bean
#ManagedBean
#ViewScoped
public class RegBean implements Serializable{
private static final long serialVersionUID = 1L;
static Logger log = LoggerFactory.getLogger(RegBean.class);
private String ssn;
private boolean showCreateUser = false;
public void confirmYes(){
setShowCreateUser(true);
}
public String confirmNo(){
log.info("In retrieveRegistration");
FacesContext fc = FacesContext.getCurrentInstance();
fc.addMessage("registrationError", new FacesMessage(
FacesMessage.SEVERITY_ERROR,
"Error. Contact customer service",
"Error. Contact customer service"));
return "/registration/registrationError";
}
public String submitRegistration() {
log.info("In submitRegistration");
FacesContext fc = FacesContext.getCurrentInstance();
return "/secured/home";
}
public String getSsn() {
return ssn;
}
public void setSsn(String ssn) {
this.ssn = ssn;
}
public boolean isShowCreateUser() {
return showCreateUser;
}
public void setShowCreateUser(boolean showCreateUser) {
this.showCreateUser = showCreateUser;
}
}
<p:commandButton id="btnConfirmNo" value="No" ajax="false"
action="#{regBean.ConfirmNo}"
styleClass="button" style="height:35px;"/>
In above code ,you've set action to be "ConfirmNo". I don't see any method as such.
Change above code as :
<p:commandButton id="btnConfirmNo" value="No" ajax="false"
action="#{regBean.agentConfirmNo}"
styleClass="button" style="height:35px;"/>
Now, it will invoke the method agentConfirmNo from your registration bean.
I hope that helps.

Primefaces ajax pagination not working

I have following jsf page, in which datatable is populated via ajax request from database. Problem is, after pushing another page button on pagination bar, table shows no results. Changing scope of backing bean to session helps, but it is not a solution. Why it is happening?
<h:form>
<h:panelGrid columns="2" cellpadding="8" style="width: 545px">
<h:panelGroup>
<p:outputLabel value="Client name: " for="searchString" />
<br />
<p:inputText id="searchString" title="searchString" value="#{findClientBean.searchString}" />
</h:panelGroup>
<h:panelGroup>
<br />
<p:message for="searchString" />
</h:panelGroup>
<p:commandButton value="Search" styleClass="pCommandButton" >
<f:ajax execute="searchString" listener="#{findClientBean.findClient}" render=":resultTable" />
</p:commandButton>
</h:panelGrid>
</h:form>
<br />
<p:dataTable id="resultTable" var="client" value="#{findClientBean.resultList}" paginator="true" rows="10"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="5,10,15" paginatorPosition="bottom">
<p:column headerText="Search results">
<h:outputLink value="../temp.xhtml?id=#{client.id}">#{client.firstName} #{client.lastName}</h:outputLink>
</p:column>
</p:dataTable>
<h:form>
Backing bean code:
#Named
#RequestScoped
public class FindClientBean implements Serializable {
#Inject
private ClientDAO clientDAO;
#NotNull(message="Search string cannot be empty")
private String searchString;
private List<Client> resultList;
public void findClient() {
resultList = clientDAO.findClientByNameOrLastnamePart(searchString);
}
public void setResultList(List<Client> resultList) {
this.resultList = resultList;
}
public List<Client> getResultList() {
return resultList;
}
public String getSearchString() {
return searchString;
}
public void setSearchString(String searchString) {
this.searchString = searchString;
}
}
Your Client resultList is being populated whenever the user presses the Search button.
As the collection is inside a RequestScoped bean, the resultList will be erased as soon as it is sent back to the View (along with the entire bean).
As a result, when the user tries to navigate to another page (thus making a second request) the component won't find a populated resultList anymore and a "No records found" message will be displayed.
"Promote" you bean to ViewScoped (or any scope that would make your bean live longer).
#Named
#ViewScoped
public class FindClientBean implements Serializable{
(...)
}

JSF 2.0 AJAX: jsf.ajax.request to call method not only rerender an area of page

I'm looking for a soultion of the following problem:
_The is a list of links with different types of cars.
_The user can click on each car in the list and a ajax request should be sent.
_The response of the ajax request should be dependent on the id (of each car) and displayed in an panelGroup.
So what I need is a possibility to call a method on the backing-bean. Additionally, this method should be called with a car id as its parameter.
My code so far looks like:
...
function showDetails(detailsFor){
jsf.ajax.request(this, event, {render: 'form1:carDetails'});
}
...
<ul>
<ui:repeat value="#{carTree.getCars)}" var="car">
<h:outputScript name="jsf.js" library="javax.faces" target="head" />
<li onclick="showDetails(#{car.id});">#{car.name}</li>
</ui:repeat>
</ul>
...
<h:panelGroup id="carDetails" layout="block" style="float:left;">
// need the details of each 'selected /clicked' car here
</h:panelGroup>
...
And the method in the backing bean should look like:
public class CarTree {
...
public String getCarDetails(int carid){
return "The car details for the car id "+carid+" are......";
}
...
}
I've no idea how to call a method by using the new JSF 2.0 AJAX functionality. Please, help me...
Use f:setPropertyActionListener to pass a object from JSF page to your backend. This tag is especially useful when you are using repeatable components like datatable
No need to use raw JavaScript, you can use <f:ajax />. Plus instead of worrying about Car id and all, just send it completely to backing bean.
Here is a sample example:
The Car class:
public class Car {
int id;
String brand;
String color;
public Car(int id, String brand, String color) {
this.id = id;
this.brand = brand;
this.color = color;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
}
The CarTree class:
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
#ManagedBean(name = "CarTree")
#RequestScoped
public class CarTree {
List<Car> carList;
Car selectedCar;
public Car getSelectedCar() {
return selectedCar;
}
public void setSelectedCar(Car selectedCar) {
this.selectedCar = selectedCar;
}
public List<Car> getCars() {
return carList;
}
public void setCars(List<Car> carList) {
this.carList = carList;
}
public CarTree() {
carList = new ArrayList<Car>();
carList.add(new Car(1, "jaguar", "grey"));
carList.add(new Car(2, "ferari", "red"));
carList.add(new Car(3, "camri", "steel"));
}
}
The JSF page:
<?xml version='1.0' encoding='UTF-8' ?>
<!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:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body id="mainBody">
<h:form id="carForm">
<h:dataTable value="#{CarTree.cars}" var="car">
<h:column>
<h:outputText value="#{car.id}"/>
</h:column>
<h:column>
<h:outputText value="#{car.brand}"/>
</h:column>
<h:column>
<h:outputText value="#{car.color}"/>
</h:column>
<h:column>
<h:commandButton value="Show Car Detail" >
<f:setPropertyActionListener target="#{CarTree.selectedCar}" value="#{car}"/>
<f:ajax render=":carForm:carDetails" />
</h:commandButton>
</h:column>
</h:dataTable>
<h:panelGroup id="carDetails" layout="block" style="float:left;">
<h:outputText value="#{CarTree.selectedCar.id}" />
<h:outputText value="#{CarTree.selectedCar.brand}" />
<h:outputText value="#{CarTree.selectedCar.color}" />
</h:panelGroup>
</h:form>
</h:body>
</html>
Hope this helps.
I haven't tested myself, but I'd suggest you try something like this (assuming your class CarTree is #Named and, therefore, can be referred to inside the JSF page using the name carTree):
<ul>
<ui:repeat value="#{carTree.getCars)}" var="car">
<li><h:commandLink action="#{carTree.getCarDetails(car.id)}" value="#{car.name}">
<f:ajax render="carDetails" />
</h:commandLink></li>
</ui:repeat>
</ul>
...
<h:panelGroup id="carDetails" layout="block" style="float:left;">
// need the details of each 'selected /clicked' car here
</h:panelGroup>
I think the contents of the action property in the <h:commandLink /> can also be coded as the listener property in the <f:ajax /> tag. Don't know if there's any difference...
If you don't want to use <h:commandLink /> you could replace it with <h:outputText /> and add the property event="click" to the <f:ajax /> tag. I think that would work as well. In this case, the method call would have to be in the listener property of the <f:ajax /> tag.

Resources