I've two session scoped beans I need to pass values between them through f:setPropertyActionListener but I cant read it from receivable end.
<p:selectOneListbox style="height: 100%; width: 100%" id="lstSubject" required="true" requiredMessage="Please select any Subject"
value="#{chooseSubExamManagedBean.subId}" >
<f:selectItems value="#{chooseSubExamManagedBean.mapSubjects}" />
</p:selectOneListbox>
user chooses the subject and I've to pass this id from p:command button to another bean
<p:commandButton id="cmdProceed" value="Proceed" action="#{chooseSubExamManagedBean.gotoFillMarks}" >
<f:setPropertyActionListener target="#{fillMarksManagedBean.subId}" value="#{chooseSubExamManagedBean.subId}" />
</p:commandButton>
the managed bean fillMarksManagedBean
#Named(value = "fillMarksManagedBean")
#javax.enterprise.context.SessionScoped
public class FillMarksManagedBean implements Serializable{
private int SubId;
private String ExamDetail;
public void setSubId(int SubId) {
this.SubId = SubId;
}
public int getSubExamId() {
return SubExamId;
}
and use that subId in
#PostConstruct
public void init() {
ExamDetail = clsFillMarks.getExamDetail(SubId);
}
...
How do i do this?
Thanks in advance
The reason why the topic has "kind of" is because I have an example in JSF 2.2 where I use a commandButton and call a bean function twice (depending on the url). It's basically the same code, which executes only in one example.
Here's the code with the description of the "error" below the code:
User bean
#ManagedBean
#RequestScoped
public class User {
private String name;
private String surname;
private int age;
private int id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public User(String name, String surname, int age, int id) {
super();
this.name = name;
this.surname = surname;
this.age = age;
this.id = id;
}
public User(){}
}
UsersBean bean:
#ManagedBean
#SessionScoped
public class UsersBean {
private List<User> listOfUsers = new ArrayList<User>();
private String passedParameter;
public UsersBean() {
listOfUsers.add(new User("Tywin", "Lannister", 60, 1));
listOfUsers.add(new User("Tyrion", "Lannister", 30, 2));
listOfUsers.add(new User("Jaime", "Lannister", 31, 3));
listOfUsers.add(new User("Cercei", "Lannister", 29, 4));
listOfUsers.add(new User("John", "Snow", 31, 5));
}
public List<User> getAll() {
System.out.println("getAall is called.");
return listOfUsers;
}
public User getDetails() {
passedParameter = (String) FacesContext.getCurrentInstance()
.getExternalContext().getRequestParameterMap().get("userID");
int id = Integer.parseInt(passedParameter);
User selected = null;
for (User u : listOfUsers) {
if (u.getId() == id) {
selected = u;
}
}
return selected;
}
public String addUser(User u) {
System.out.println("addUser is called.");
if (u.getId() != 0) {
for (User edit : listOfUsers) {
if (edit.getId() == u.getId()) {
System.out.println("Found it!");
edit.setAge(u.getAge());
edit.setName(u.getName());
edit.setSurname(u.getSurname());
}
}
} else {
u.setId(listOfUsers.size() + 1);
listOfUsers.add(u);
}
return "";
}
}
users.xhtml:
<f:view>
<!-- http://stackoverflow.com/questions/8083469/method-must-have-signature-string-method-etc-but-has-signature-void -->
<h:dataTable value="#{usersBean.all}" var="u">
<h:column>
<f:facet name="header">
User ID
</f:facet>
#{u.id}
</h:column>
<h:column>
<f:facet name="header">
Name
</f:facet>
#{u.name}
</h:column>
<h:column>
<f:facet name="header">
Details
</f:facet>
<h:link outcome="users" value="edit user">
<f:param name="userID" value="#{u.id}"></f:param>
<f:param name="action" value="edit"></f:param>
</h:link>
<h:link outcome="usersDetails" value="get details">
<f:param name="userID" value="#{u.id}"></f:param>
</h:link>
</h:column>
</h:dataTable>
<h:panelGroup rendered="#{param['action'] == 'edit'}">
<h1>Edit!</h1>
<h:form>
<ui:param name="editUser" value="#{usersBean.details}"></ui:param>
<h:outputText value="Name"></h:outputText>
<h:inputText value="#{editUser.name}"></h:inputText> <br />
<h:outputText value="Surname"></h:outputText>
<h:inputText value="#{editUser.surname}"></h:inputText> <br />
<h:outputText value="Age"></h:outputText>
<h:inputText value="#{editUser.age}"></h:inputText> <br />
<h:commandButton action="#{usersBean.addUser(editUser)}" value="Edit" type="submit"> </h:commandButton>
</h:form>
</h:panelGroup>
<h:panelGroup rendered="#{empty param['action']}">
<h1>Add!</h1>
<h:form>
<h:outputText value="Name"></h:outputText>
<h:inputText value="#{user.name}"></h:inputText>
<h:outputText value="Surname"></h:outputText>
<h:inputText value="#{user.surname}"></h:inputText>
<h:outputText value="Age"></h:outputText>
<h:inputText value="#{user.age}"></h:inputText>
<h:commandButton action="#{usersBean.addUser(user)}" value="Add" type="submit"></h:commandButton>
</h:form>
</h:panelGroup>
</f:view>
OK, so, everything works perfectly. usersBean.addUser adds the user. If I add another inputText for ID and I put in an existing ID, the corresponding function updates the values. So, addUser function works as expected.
The problem is in case of
<h:panelGroup rendered="#{param['action'] == 'edit'}">
as you can see in the xhtml above, the code is basically the same, with the sole exception that I fill in the data of the user that was selected. This works, I get the appropriate data into input fields, but when I change them and click Edit, nothing happens. The function is not called! whereas in case of add, the function is called and it works.
It appears as if there is no action defined in case of edit, it only reloads the page (submit) without the actual action addUser.
How is this caused and how can I solve it?
It's because #{param['action'] == 'edit'} didn't evaluate true during processing the form submit and therefore the <h:panelGroup> is basically not rendered during processing the form submit, including the <h:commandButton> sitting in there. The form submit namely did not pass that parameter back to JSF. This way JSF won't see the <h:commandButton> and therefore never be able to decode and queue its action event. You need to make sure that all your rendered conditions evaluate the same during processing the form submit as they were during displaying the form (this is part of JSF's safeguard against tampered/hacked requests wherein the enduser would otherwise be able to execute unrendered command buttons like admin-only buttons).
So, you basically need to retain that parameter during the postbacks as well so that the rendered expression still evaluates true during processing the form submit. This can be achieved in several ways:
Add it as <f:param> inside the <h:commandButton> of relevance:
<h:commandButton action="#{usersBean.addUser(editUser)}" value="Edit" type="submit">
<f:param name="action" value="#{param.action}" />
</h:commandButton>
(note: param['action'] and param.action are equivalent; those brackets are only useful if the 'action' contains periods, or represents another variable)
Set it as a bean property by <f:viewParam>. Requirement is that the bean needs to be in view scope or broader. You've it in the session scope already, which is okay (but which is IMO way too broad, but that aside):
<f:metadata>
<f:viewParam name="action" value="#{usersBean.action}" />
</f:metadata>
...
<h:panelGroup rendered="#{usersBean.action}">
...
</h:panelGroup>
If you're already using JSF utility library OmniFaces, use its <o:form> instead of <h:form> which enables you submit to the current request URI instead of to the current JSF view ID. This way the GET request string will automagically be retained and you don't need to copypaste <f:param> over all command buttons like as in #1:
<o:form useRequestURI="true">
...
</o:form>
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated - point 6
I am learning JavaEE and I am playing around with ajax call with jsf and managedbean. I am trying to display the text as soon as i change the value from the drop down list. I see many people have the same problem on stackoverflow and i try to follow answers that are marked as accepted but I still can't make it work. Can someone please tell me where my error is?
Here is the jsf code:
<h:form>
<h:selectOneMenu id="productlist" value="#{productRepoMB.selectedProduct}">
<f:selectItems value="#{productRepoMB.productList}" var="product" itemValue="#{product.productID}" />
<f:ajax event="valueChange"
render="result"
listener="#{productRepoMB.selectMenuListener}" />
</h:selectOneMenu>
text changed: <h:outputText id="result" value="#{productRepoMB.text}" />
</h:form>
Here is managed bean code, Products list is populated from a database:
#Named
#RequestScoped
public class ProductRepoMB implements Serializable {
#EJB
private ProductsRepo productRepo;
private Products selectedProduct;
private List<Products> productList;
private String text="init text"; //use for testing ajax call
public ProductRepoMB() {
}
public Products getSelectedProduct() {
return selectedProduct;
}
public List<Products> getProductList() {
productList = productRepo.findAll();
return productList;
}
//The following code are used to testing ajax only!
public void selectMenuListener(AjaxBehaviorEvent e) {
setText("changed!");
}
public String getText() {
return text;
}
public void setText(String text){
this.text = text;
}
}
In my facelet, I have the below commandLink:
<h:form>
<p:commandLink id="excelExport" action="#{studentBean.exportReport()}" ajax="false">
<f:param name="type" value="EXCEL" />
<p:graphicImage library="img" name="excel.png" width="20" />
</p:commandLink>
</h:form>
This is what I am having in my backing bean:
#ManagedBean
#RequestScoped
public class StudentBean implements Serializable {
.............
#ManagedProperty(value = "#{param.type}")
private String typeOfExport;
.............
public void preRender(ComponentSystemEvent event) {
System.out.println("Inside prerender");
if (FacesHelper.isAjaxRequest()) {
return;
}
}
.............
public void exportReport() {
System.out.println("Type of Report is: " + typeOfExport);
}
}
Now I would like to execute the method exportReport once I click on the commandLink. But what is happening here is that after executing the method, it is going to preRender again. I don't want to render the entire form again. Any idea what mistake I am doing here?
I'm trying to improve my web app. I read this article http://balusc.blogspot.com/2011/01/jsf-20-tutorial-with-eclipse-and.html and tried to implement some of the ajax stuff (I'm very new to JSF and Ajax).
So the first form works as expected, but when I pass to the second page the message malformedXML: During update: accessForm:passMessage not found is shown in an alert box.
Can anyone explain me why?
<h:form id="accessForm">
<h:panelGrid columns="3">
<h:outputLabel for="user" value="Usuario:"
style="float: right" />
<h:inputText id="user" value="#{userVerifier.username}"
required="true"
requiredMessage="Introduzca su nombre de usuario.">
<f:ajax event="blur" render="userMessage" />
</h:inputText>
<h:message id="userMessage" for="user" style="color: #FF0000;" />
<h:outputLabel for="pass" value="ContraseƱa:"
style="float: right" />
<h:inputSecret id="pass" value="#{userVerifier.password}"
required="true"
requiredMessage="Introduzca su contraseƱa." redisplay="true">
<f:ajax event="blur" render="passMessage" />
</h:inputSecret>
<h:message id="passMessage" for="pass" style="color: #FF0000;" />
<h:panelGroup />
<h:commandButton value=" Entrar " action="#{userVerifier.check}"
style="float: right" >
<f:ajax execute="#form" render="#form" />
</h:commandButton>
<h:messages globalOnly="true" layout="table" />
</h:panelGrid>
</h:form>
Thanks in advance.
Update
Here's the Bean code:
#ManagedBean
#SessionScoped
public class UserVerifier{
private String username;
private String password;
private String dependencia;
private String tipoUsuario;
private final Database db = new Database();
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDependencia() {
return dependencia;
}
public void setDependencia(String dependencia) {
this.dependencia = dependencia;
}
public String getTipoUsuario() {
return tipoUsuario;
}
public void setTipoUsuario(String tipoUsuario) {
this.tipoUsuario = tipoUsuario;
}
public String check() {
String isValidUser = db.checkUser(username, password);
if (isValidUser.equals("T")) {
dependencia = db.getDependencia(username, password);
tipoUsuario = db.getTipoUsuario(username);
System.out.println("tipoDepe: " + dependencia);
System.out.println("tipoUser: " + tipoUsuario);
if (dependencia != null && tipoUsuario != null) {
return "upload-file";
} else {
setUsername("");
setPassword("");
return "index";
}
} else if (isValidUser.equals("F")) {
setUsername("");
setPassword("");
return "index";
} else {
return "error-pnf";
}
}
}
This error indicates a race condition in handling ajax requests. The ajax request of the action method occurred before the ajax request of the blur validation. Try adding ?faces-redirect=true to the navigation outcome value of the action method. JSF should then surely block all open ajax requests in the queue.
public String check() {
// ...
return "nextpage?faces-redirect=true";
}
Using (default) forward on POST navigation is a poor practice anyway as the enduser would otherwise end up with an unchanged URL in browser address bar and a non-bookmarkable page. See also When should I use h:outputLink instead of h:commandLink?