Why does id remain zero? [duplicate] - jsf

This question already has answers here:
Creating master-detail pages for entities, how to link them and which bean scope to choose
(2 answers)
Closed 3 years ago.
I'm working on one school project, where i need to use JSF to make CRUD app.
I'm using MySQL database, and managed to make list of all objects, delete button, and i have trouble with edit button.
When i click on edit it redirect me to edit.xhtml page, get id and fill all fields based on that id.
When i click update button on edit page, it always change customer with id=0.
I have one java doc with getter, setter and methods
have two views index.xhtml and edit.xhtml
and one page with method for connection with database.
All other methods work fine, except update.
Customer.java
#ManagedBean
#RequestScoped
public class Customer {
private int id;
private String username;
private String adress;
private int quantity;
private double price;
private Map<String, Object> sessionMap = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
public String edit() {
FacesContext fc = FacesContext.getCurrentInstance();
Map<String, String> params = fc.getExternalContext().getRequestParameterMap();
String primarId = params.get("action");
System.out.println(primarId);
try {
DatabaseConnection dbc = new DatabaseConnection();
Connection connection = dbc.getConnection();
Statement st = connection.createStatement();
ResultSet rs = st.executeQuery("select * from customer where customer_id=" + primarId);
Customer customer = new Customer();
rs.next();
customer.setUsername(rs.getString("username"));
customer.setAdress(rs.getString("adress"));
customer.setQuantity(rs.getInt("quantity"));
customer.setPrice(rs.getDouble("price"));
sessionMap.put("editcustomer", customer);
} catch (SQLException ex) {
System.out.println(ex);
}
return "/edit.xhtml?faces-redirect=true";
}
public String updateCustomer() {
FacesContext fc = FacesContext.getCurrentInstance();
Map<String, String> params = fc.getExternalContext().getRequestParameterMap();
String fieldId = params.get("action");
System.out.println(fieldId);
try {
DatabaseConnection dbc = new DatabaseConnection();
Connection connection = dbc.getConnection();
PreparedStatement ps = connection.prepareStatement("update customer set username=?,adress=?,quantity=?,price=? where customer_id=?");
ps.setString(1, username);
ps.setString(2, adress);
ps.setInt(3, quantity);
ps.setDouble(4, price);
ps.setInt(5, id);
System.out.println(id);
ps.executeUpdate();
} catch (SQLException ex) {
System.out.println(ex);
}
return "/index.xhtml?faces-redirect=true";
}
edit.xhtml
<?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://xmlns.jcp.org/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<center>
<h:form>
Username: <h:inputText value="#{editcustomer.username}"></h:inputText> <br/>
Adress: <h:inputText value="#{editcustomer.adress}"></h:inputText> <br/>
Quantity: <h:inputText value="#{editcustomer.quantity}"></h:inputText> <br/>
Price: <h:inputText value="#{editcustomer.price}"></h:inputText> <br/><br/>
<h:commandButton value="Update" action="#{editcustomer.updateCustomer()}">
<f:param name="action" value="#{editcustomer.id}" />
</h:commandButton>
</h:form>
</center>
</h:body>
</html>
when I run this code the ID stays 0

I think the problem is the #RequestScoped annotation in the bean. With this annotation data only "lives" in the current page. As you are redirecting to another URL (altough it is the same one), you lose your changes (more taking into account that you are putting the customer in the session map. Try using #SessionScoped instead.
Hope it works.

Related

h:dataTable displays the correct number but blank rows

My JSF application is behaving strangely, and I ask colleagues to help me identify a solution.
The application fetches data from the database through Facade+DAO classes, and through debug and println I can state that the object collection is correct (in the example below, the collection contains the 5 objects and their attributes), however, when passing this collection to the Primefaces page, dataTable does not display the attributes, it becomes clear that the the amount of rows is correct but the attributes are not displayed as shown in the figure.
I researched other posts, but the errors described do not resemble mine:
after filtering Empty rows blank rows displayed while paging in the datatable using Primefaces
primefaces datatable is showing blank rows. Showing the same number of rows as the records in backed list
Since the managed bean is reposting the collection correctly, I figured the issue should be on display (ie on the JSF page), and to try to find where the fault could be, I created a page without using Primefaces or Facelets, just pure JSF components, but the failure persisted. The basic code looks like this:
Here are the code snippets:
simple page
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<link href="scripts/teste.css" rel="stylesheet" type="text/css" media="all" />
</h:head>
<h:body>
<h:form>
<h:dataTable value="#{coletaMB.coletas}" var="coleta"
styleClass="order-table"
headerClass="order-table-header"
rowClasses="order-table-odd-row,order-table-even-row">
<h:column>
<f:facet name="header">Nr. Setor</f:facet>
<h:outputText value="#{coleta.setor.numero}"/>
---- #{coleta.setor.numero} ----
</h:column>
</h:dataTable>
</h:form>
With this simple code, the page looks like this:
managed bean
#ManagedBean(name="coletaMB")
#SessionScoped
public class ColetaMB{
#ManagedProperty(name="coleta", value="#{coleta}")
private Coleta coleta;
#ManagedProperty(name="coletaFacade", value="#{coletaFacade}")
private ColetaFacade coletaFacade;
private List<Coleta> coletas;
public List<Coleta> getColetas(){
if(coletas == null){
coletas = getListColetas();
}
return coletas;
}
private List<Coleta> getListColetas(){
coletas = new ArrayList<Coleta>();
try {
coletas = coletaFacade.getColetas();
return coletas;
} catch (DAOException e) {
(...)
}
}
(...)
}
Coleta.java
public class Coleta {
private int ano;
private Setor setor;
private int mes;
private int semana;
private int numeroEntrevista;
(*)getters and setter
}
Setor.java
public class Setor {
private Agencia agencia;
private String numero;
private String upa;
(*)getters and setters
}
Agencia.java
public class Agencia {
private int idAgencia;
private String nome;
(*)getters and setters
}
Facade
public List<Coleta> getColetas() throws DAOException {
return dao.getColetas();
}
DAO
#Value("#{queries.sql01}")
private String sql01;
public List<Coleta> getColetas() throws DAOException {
try{
RowMapper<Coleta> mapper = getRowMapper();
return getJdbcTemplate().query(sql01, mapper);
} catch (DataAccessException de) {
de.printStackTrace();
throw new DAOException(de.getMessage());
}
}
private RowMapper<Coleta> getRowMapper() {
return new RowMapper<Coleta>() {
public Coleta mapRow(ResultSet rs, int rowNum) throws SQLException {
Agencia ag = new Agencia();
ag.setIdAgencia(rs.getInt(1));
ag.setNome(rs.getString(2));
Setor s = new Setor();
s.setAgencia(ag);
s.setUpa(rs.getString(3));
s.setNumero(rs.getString(4));
Coleta c = new Coleta();
c.setSetor(s);
c.setAno(rs.getInt(5));
c.setMes(rs.getInt(6));
c.setSemana(rs.getInt(7));
c.setNumeroEntrevista(rs.getInt(8));
return c;
}
};
}
In getListColetas, I inserted a println to verify the collection and it is complete, that is, each object 'coleta' has the object 'setor' and each 'setor' has the object 'agencia'. But, following the suggestion of using 'empty' on the JSF page,
<h:outputText value="#{empty coleta} - #{empty coleta.setor} - #{empty coleta.setor.numero}"/>
the return was false - true - true, and I don't know why.
My complete application is using the following libraries and dependencies (Spring is only used for DI and DAO classes):
Resolved: in dataTable tag, I changed the attribute var="coleta" to var="c", like this:
<h:dataTable value="#{coletaMB.coletas}" var="c"
styleClass="order-table"
headerClass="order-table-header"
rowClasses="order-table-odd-row,order-table-even-row">
<h:column>
<f:facet name="header">Nr. Setor</f:facet>
<h:outputText value="#{c.setor.numero}"/>
---- #{c.setor.numero} ----
</h:column>
</h:dataTable>
I imagine JSF was conflicting with the #ManagedProperty 'coleta' in ColetaMB, although I understand that the var attribute is specific to varying collection objects delivered to dataTable.

Can you set an Ajax response action to a PrimeFace component which's html is generated in a Bean?

Dear friendly strangers,
using PrimeFaces 7.0 on JSF 2.2 I'm generating html-Code in my Bean and inject it in my xhtml with <h:outputText value="#{myBean.myHtml}" escape="false"/>. This naturally doesn't work with <p:.../> components, as they themselves generate/render actual html. The way I alter the data from my Database to get the final html is too complicated for html functions though, so I still wanna do it in my Java-Beans instead of using lots of ui:repeat and hypercomplex custom styles - even though I know this is not how jsf/PrimeFaces is meant to be used. Now checking the actual rendered html e.g. of a p:commandLink it gives
<a id="myContainerID:myComponentID" href="#" class="ui-commandlink ui-widget" onclick="PrimeFaces.ab({s:"myContainerID:myComponentID",f:"myContainerID"});return false;">myComponentValue</a>
,which I can generate easily, but the response-action called when receiving the component's Ajax request (s:"myContainerID:myComponentID") will be missing, which seems to be saved somewhere in the moment the actual html is generated with <p:...>.
Is there a way to manually set that response-action, if so how/where?
EDIT: Since (quoting PrimeFaces.ab function)
//ajax shortcut
ab: function(cfg, ext) {
return PrimeFaces.ajax.AjaxRequest(cfg, ext);
}
The PrimeFaces.ajax.AjaxRequest can be asynchronous or synchronous. The AjaxRequest uses the AjaxUtils, which handles all
send, process, response, and update.
PrimeFaces.ajax.AjaxRequest = function(cfg, ext) {
cfg.ext = ext;
if(cfg.async) {
return PrimeFaces.ajax.AjaxUtils.send(cfg);
}
else {
return PrimeFaces.ajax.Queue.offer(cfg);
} }
I suppose the answer, if there is any, should lay somewhere in AjaxUtils, but couldn't find it yet.
Thanks helluvalot for any suggestion/help.
EDIT 2: I did eventually manage to transcribe it all to the xhtml with nested ui:repeats and lots of custom styles, I'm still curious though whether there's a way to do it with in-Bean-generated html.
ExampleCode
myBean:
#ManagedBean(name = "myBean")
#SessionScoped
public class myBean {
private String html1;
private String html2;
#PostConstruct
public void init() {
html1 = "<p:commandLink id=\"myComponentID\" value=\"myComponentValue\" "
+ "action=\"#{someBean.doSomething()}\"";
html2 = "<a id=\"myContainerID:myComponentID\" "
+ "href=\"#\" class=\"ui-commandlink ui-widget\" "
+ "onclick=\"PrimeFaces.ab({s:\"myContainerID:myComponentID\","
+ "f:\"myContainerID\"});"
+ "return false;\">1. myComponentValue</a>";
}
public String getHtml1() {
return html1;
}
public void setHtml1(String html1) {
this.html1 = html1;
}
public String getHtml2() {
return html2;
}
public void setHtml2(String html2) {
this.html2 = html2;
}
}
myIndex.xhtml:
<h:html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
>
<h:head>
</h:head>
<h:body>
<h:form id="myContainerID">
<h:outputText value="#{myBean.html1}" escape="false" />
<h:outputText value="#{myBean.html2}" escape="false" />
</h:form>
</h:body>
</h:html>

Value of <h:selectBooleanCheckbox> is not updated according to backing bean value

I'm using JSF2 and Tomcat server. I programmed a simple example in which:
User Selects a faculty from "h:selectOneMenu"
Upon selection, the value of "h:inputText" is changed to "odd" or "even" based on facultyNo
Also, upon selection, the value of "h:selectBooleanCheckBox" is changed to "checked" if facultyNo is even and "not checked" if facultyNo is odd
Everything works fine for "h:inputText". On the other hand, the value of "h:selectBooleanCheckBox" does not change. Why is this happening?
By the way, the use of boolean value inside a HashMap is intentional because the project I'm working on has lots of boolean values in a HashMap. So, replacing the Hashmap with a simple boolean property and using a getter and a setter for it is definitely not a solution for my case.
The code for the xhtml page is below:
<!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">
<head>
<title>Dummy Title</title>
</head>
<body>
<h:form>
<label for="faculty">Faculty</label>
<h:selectOneMenu id="faculty" value="#{test.selectedFaculty}" converter="faccon" valueChangeListener="#{test.facultyChange}" onchange="submit()">
<f:selectItems value="#{start.app.faculties}"/>
</h:selectOneMenu>
<h:selectBooleanCheckbox id="mycheck" value="#{test.x.get(0)}"></h:selectBooleanCheckbox>
<h:outputText value="#{test.res}"></h:outputText>
<h:commandButton value="Save" action="#{test.saveChoices}" />
</h:form>
</body>
</html>
The code for the backing bean is below
import java.io.Serializable;
import java.util.HashMap;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.event.ValueChangeEvent;
import com.myWork.Application;
import com.myWork.Faculty;
#ManagedBean(name="test")
#RequestScoped
public class TestBean implements Serializable
{
private HashMap<Integer,Boolean> x;
private String res;
private Faculty selectedFaculty;
#PostConstruct
public void init(){
Application app = Application.getInstance();
selectedFaculty = app.getFaculties()[0];
x = new HashMap<Integer, Boolean>();
if (selectedFaculty.getFacultyNo()%2==0)
{
x.put(0, true);
res = "even";
}
else
{
x.put(0, false);
res = "odd";
}
}
public HashMap<Integer,Boolean> getX() {
return x;
}
public void setX(HashMap<Integer,Boolean> x) {
this.x = x;
}
public Faculty getSelectedFaculty() {
return selectedFaculty;
}
public void setSelectedFaculty(Faculty selectedFaculty) {
this.selectedFaculty = selectedFaculty;
}
public String getRes() {
return res;
}
public void setRes(String res) {
this.res = res;
}
public void facultyChange(ValueChangeEvent e){
Faculty fac = (Faculty) e.getNewValue();
if (fac.getFacultyNo()%2==0)
{
x.put(0, true);
res = "even";
}
else
{
x.put(0, false);
res = "odd";
}
}
public String saveChoices(){
return "test";
}
}
Any help is greatly appreciated.
Actually your problem is not related to JSF, it is related to EL. in your case, EL treat you map keys as long not int, so you should change your map to be:
HashMap<Long, Boolean> map = new HashMap<>();
and set the key values as follows :
map.put(0L, false);
map.put(1L, true);
to force it to be auto-boxed to long.
Note: the problem described in detailed in the following question :
EL access a map value by Integer key
In order to send updates to a different component, you can make use of partial page rendering by making Ajax calls to send parameters to Managed bean.
Within <h:selectBooleanCheckBox>
<h:selectOneMenu id="faculty" value="#{test.selectedFaculty}" converter="faccon" valueChangeListener="#{test.facultyChange}">
<f:selectItems value="#{start.app.faculties}"/>
</h:selectOneMenu>
<h:selectBooleanCheckbox id="mycheck" valueChangeListener="#{test.facultyChange}" value="#{test.x.get(0)}">
<f:ajax event="change" execute="#form" render="faculty"/>
</h:selectBooleanCheckbox>
Edit: Removed call to onSubmit() in selectOneMenu. introduced an ajax call in selectBooleanCheckbox for partial page refresh.
Refer full solution at this post.

Passing Parameter to complete method of primefaces inputtextarea control

In JSF & Primefaces web application, I want to pass a value for the complete method of primefaces input text area control. I have tried it as follows.
JSF file
<p:inputTextarea id="txtMicMemoVal"
value="#{patientReportController.memoEnterVal}"
style="min-width: 200px;"
completeMethod="#{investigationItemValueController.completeValues}" >
<f:attribute name="ii" value="#{pv.investigationItem}" />
<f:ajax event="blur" execute="#this"
listener="#{patientReportController.saveMemoVal(pv.id)}" ></f:ajax>
</p:inputTextarea>
Relevant Backing Bean
public List<String> completeValues(String qry) {
System.out.println("completing values");
FacesContext context = FacesContext.getCurrentInstance();
InvestigationItem ii;
try {
ii = (InvestigationItem) UIComponent.getCurrentComponent(context).getAttributes().get("ii");
System.out.println("ii = " + ii);
} catch (Exception e) {
ii = null;
System.out.println("error " + e.getMessage());
}
Map m = new HashMap();
String sql;
sql = "select v.name from InvestigationItemValue v "
+ "where v.investigationItem=:ii and v.retired=false and"
+ " (upper(v.code) like :s or upper(v.name) like :s) order by v.name";
m.put("s","'%"+ qry.toUpperCase()+"%'");
m.put("ii", ii);
List<String> sls = getFacade().findString(sql, m);
System.out.println("sls = " + sls);
return sls;
}
But the backing bean method is not fired when i enter text to input text area. But if I remove the f:attribute, backing bean is fired. But I want that parameter as well for functionality.
Thanks in advance to direct me to over come this issue.
Interesting question. Primefaces bounds you to receive only a String parameter in your completion method, so the only solution I see is evaluating your expression at server side, when completion function gets called.
I suppose you've got an iteration (either ui:repeat or p:dataTable) where each id differs from the previous one. If you don't, you can also use it.
That would be the way to go:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head />
<h:body>
<h:form>
<ui:repeat var="str" value="#{bean.strings}">
<p:inputTextarea value="#{bean.value}" style="min-width: 200px;"
completeMethod="#{bean.complete}" />
</ui:repeat>
</h:form>
</h:body>
</html>
#ManagedBean
#RequestScoped
public class Bean {
public String value;
public List<String> strings = Arrays.asList("param1", "param2", "param3");
public List<String> complete(String query) {
List<String> results = new ArrayList<String>();
//Here we evaluate the current #{str} value and print it out
System.out.println(FacesContext
.getCurrentInstance()
.getApplication()
.evaluateExpressionGet(FacesContext.getCurrentInstance(),
"#{str}", String.class));
if (query.equals("PrimeFaces")) {
results.add("PrimeFaces Rocks!!!");
results.add("PrimeFaces has 100+ components.");
results.add("PrimeFaces is lightweight.");
results.add("PrimeFaces is easy to use.");
results.add("PrimeFaces is developed with passion!");
}
return results;
}
public List<String> getStrings() {
return strings;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
Note you're evaluating the current EL result for #{str} when method call performs. You'll get a different evaluation result depending on which p:inputTextArea you write to.
See also:
How to pass parameter to f:ajax in h:inputText? f:param does not work

error in taking input in jsf form

When login page is loaded the input text box is displaying #{ad.userid}. When I erased it and entered id and pwd and clicked submit button the login method is called but userid property is giving null value in bean. How can this happen and how can I solve it?
Here is the login.jsp:
<%# page contentType="text/html"%>
<%# taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%# taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<f:view>
<html>
<h:form>
<h:outputText value="Login"/>
<h:inputText value="#{ad.userid}" id="log" required="true"/>
<h:outputText value="Password" />
<h:inputSecret id="pw" value="#{ad.password}" required="true"/>
<h:commandButton value="submit" action="#{ad.login}"/>
</h:form>
</body>
</html>
</f:view>
Here is the bean's action method. The login worked successfully earlier. All db connections are set in constructor.
public String login() {
ResultSet rs;
try {
System.out.println(userid); // this is giving null
String s = "select id from slogin where id='" + userid + "'";
System.out.println(s);
rs = st.executeQuery(s);
if (rs.next()) {
String loginid = rs.getString(1);
if (userid.equals(loginid)) {
id = loginid;
return "studhome";
}
} else {
System.out.println("error");
}
} catch(Exception e) {
}
}
Getter and setter methods:
public void setpassword(String pass) {
this.password = pass;
}
public String getpassword() {
return password;
}
public void setuserid(String uid) {
this.userid = uid;
}
public String getuserid() {
return userid;
}
Please, take your time to edit your question, format it properly using the formatting code tools that StackOverflow provides. The braces will appear if you use the button with the symbol "0101010101".
The answer:
Change:
public void setuserid(String uid)
to
public void setUserid(String uid)
and also:
public void setpassword(String pass)
to
public void setPassword(String pass)
Have a look at Java Naming Conventions, JSF relies on them to access the properties of a managed bean.
Btw, try to set your backing bean to Session scope to see if it works, to discard other problems
I am not sure if this is helpful -
1) add debug(sysouts) statements in the getters and setters and use the naming conventions as said by pakore (better you can ask eclipse to generate getters and setters).
2) try to write a Phaselistener to see if all the apply request and update model phases of jsf life cycle happens.

Resources