I started study RichFaces 4.2.2 and have a problem in simple example, I have an xml:
<ui:define name="content">
<h:form>
<rich:panel style="width: 50%">
<h:panelGrid columns="2">
<h:outputText value="Name:"/>
<h:inputText id="inp" value="#{echoBean.name}">
<a4j:ajax event="keyup" render="echo count" listener="#{echoBean.countListener}"/>
</h:inputText>
<h:outputText value="Echo:"/>
<h:outputText id="echo" value="#{echoBean.name}"/>
<h:outputText value="Count:"/>
<h:outputText id="count" value="#{echoBean.count}"/>
</h:panelGrid>
<a4j:commandButton value="Submit" actionListener="#{echoBean.countListener}" render="echo, count"/>
</rich:panel>
</h:form>
</ui:define>
and a simple bean:
#Component("echoBean")
#Scope(value = "session")
public class EchoBean {
private String name;
private Integer count = 0;
//getter setter methods here
public void countListener(ActionEvent event) {
count++;
}
}
And when i try to print in inputText i have exception:
Caused by: javax.el.MethodNotFoundException: /home.xhtml #35,112 listener="#{echoBean.countListener}": Method not found: com.example.training.bean.EchoBean#d523fa.countListener()
at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:102)
at org.ajax4jsf.component.behavior.MethodExpressionAjaxBehaviorListener.processAjaxBehavior(MethodExpressionAjaxBehaviorListener.java:71)
at javax.faces.event.AjaxBehaviorEvent.processListener(AjaxBehaviorEvent.java:113)
at javax.faces.component.behavior.BehaviorBase.broadcast(BehaviorBase.java:98)
at org.ajax4jsf.component.behavior.AjaxBehavior.broadcast(AjaxBehavior.java:348)
at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:763)
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:775)
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1267)
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:82)
... 19 more
But why? With button this same listener works just fine and in docs for "listener" parameter in a4j:ajax it says that:
The expression must evaluate to a public method that takes an ActionEvent parameter, with a return type of void, or to a public method that takes no arguments with a return type of void
Why it uses countListener() without ActionEvent parameter? I don't get it.
For you to be able to use the listener attribute with RF4, your listener method should take an argument of the AjaxBehaviorEvent type, not an ActionEvent type. The other alternative approach as you can see from the error message is to define a standard java method that doesn't take arguments and has a void return type as in
public void countListener();
Why it uses countListener() without ActionEvent parameter? I don't get it.
That's the contract for the API, you're required to conform to be able to use it.
Use the bean function with the following signature
void as return type
ActionEvent object as parameter
Example for the bean function is as below
public void countListener(ActionEvent event) {}
Related
I have been trying to run AJAX example in JSF. But I am getting "class does not have the property login". But in all the examples in various websites, code is same the same.
My index.xhtml
<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>JSF AJAX Calls</title>
</h:head>
<h:body>
<h2>AJAX Example</h2>
<h:form>
<h:inputText id="inputName" value="#{userData.name}"></h:inputText>
<h:commandButton value="Login">
<f:ajax execute="inputName" render="outputMsg" />
</h:commandButton>
<br />
<hr />
<h2><h:outputText id="outputMsg" value="#{userData.login}" /></h2>
</h:form>
</h:body>
</html>
UserData.java
package com.cyb3rh4wk.test;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean(name = "userData", eager = true)
#SessionScoped
public class UserData implements Serializable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String login() {
if ("".equals(name) || name == null)
return "";
else
return "Logged in as " + name;
}
}
This is my error,
/index.xhtml value="#{userData.login}": The class 'com.cyb3rh4wk.test.UserData' does not have the property 'login'.
How do I resolve this error ?
Value and Method Expressions
The EL defines two kinds of expressions: value expressions and method expressions. Value expressions can either yield a value or set a value. Method expressions reference methods that can be invoked and can return a value.
Example of a value expression according to the above definition in your code is:
userData.name
In the following tag definition:
<h:outputText id="outputMsg" value="#{userData.login}" />
you are not using a value expression but rather a method expression because login is not a simple JavaBean getter returning the value of a bean property.
So you have to change the above line as:
<h:outputText id="outputMsg" value="Logged in as : #{userData.name}" />
And remove your login or use it for navigation purpose (that is why it is there).
Here is the reason (taken from JSF 2.0 specification) why you have to pass a value expression to an output component instead of a method expression:
4.1.10 UIOutput
UIOutput (extends UIComponentBase; implements ValueHolder) is a component that has a value, optionally retrieved from a model tier bean via a value expression (see Section 5.1 “Value Expressions”), that is displayed to the
user. The user cannot directly modify the rendered value; it is for display purposes only:
I'm trying to set a enum property with setPropertyActionListener but I'm not sure how to do it. Here's the entity:
#Entity
public class Invoice {
public enum InvoiceStatus { ACTIVE, CANCELED }
...
#Enumerated(EnumType.STRING)
private InvoiceStatus status;
...
public InvoiceStatus getStatus() {
return status;
}
public void setStatus(InvoiceStatus status) {
this.status = status;
}
And here's the command button which is suppose to set the status to ACTIVE with setPropertyActionListener
...
<h:form id="invoiceCreatedSuccessfully">
<p:dialog header="#{msg['title.success']}" widgetVar="invoiceCreatedSuccessfullyDialog" resizable="false" showEffect="fade" hideEffect="fade">
<h:panelGrid columns="2" rows="3" style="margin-bottom: 10px">
<h:outputText value="#{msg['message.invoiceCreatedSuccessfully']}" />
</h:panelGrid>
<p:commandButton value="#{msg['label.acknowledged']}" actionListener="#{invoiceManager.reload}" action="viewInvoices">
<f:setPropertyActionListener target="#{invoiceManager.invoice.status}" value="ACTIVE" />
</p:commandButton>
</p:dialog>
</h:form>
No errors are reported but the field 'status' in the DB is not being set. Can someone tell me why?
Strings are not directly converted to Enums in EL , you would need to a custom converted in your faces-config , jsf has one enum converter that should work for you,
<converter>
<converter-for-class>java.lang.Enum</converter-for-class>
<converter-class>javax.faces.convert.EnumConverter</converter-class>
</converter>
Now looking into the source code of EnumConverter , it seems like it works only if targetClass is available in converter.
So you would need to extend it to work with your enum ,
public class MyEnumConverter extends EnumConverter {
public MyEnumConverter () {
super(MyEnum.class);
}
}
<converter>
<converter-id>MyEnum</converter-id>
<converter-class>com.test.MyEnumConverter</converter-class>
</converter>
add <f:converter converterId="MyEnum"/> in your component.
If you have many Enums and to make things easy , you can have a look into omnifaces http://showcase.omnifaces.org/converters/GenericEnumConverter
I am using JSF 2.0 with Primefaces 3.4.2
I have two p:selectOneMenu, first one parent and second child, based on parent value, child component gets populated.
Parent p:selectOneMenu
<p:selectOneMenu id="empl" value="#{empMB.employee}">
<f:selectItems value="#{empMB.employeeList}" var="emp"
itemLabel="#{emp.employeeName}" itemValue="#{emp.employeeNumber}"/>
<p:ajax update="department" />
</p:selectOneMenu>
Child p:selectOneMenu
<p:selectOneMenu id="department" value="#{deptMB.department}">
<f:selectItems value="#{deptMB.loadDepartments(<??>)}" var="dept"
itemLabel="#{dept.departmentName}" itemValue="#{dept.departmentCode}"/>
</p:selectOneMenu>
I have a method in department ManagedBean called loadDepartments with one argument
public void loadDepartments(String employeeNumber)
How can I pass value to loadDepartments in child component so that it will load all the departments based on the code selected in parent component?
If I am substituting #{deptMB.loadDepartments(empMB.employee.employeeCode)} I am getting
Error Parsing: #{deptMB.loadDepartments({empMB.employee.employeeCode})}
Any help is highly appreciable?
I'd do this:
Add a list variable to your bean (and the appropriate getter): this list will hold the values for the child combo box;
Add a listener to the p:ajax call on the parent combo box: the listener populates the list of child values (you'll have access to the selected parent item inside its listener); and
Update your xhtml to use the values from the list created on step 1 instead of the loadDepartments method you're trying to invoke.
This is normally how I do this sort of thing and it should work out for you.
EDIT
Code for the page:
<p:selectOneMenu id="empl" value="#{empMB.employee}" converter="#{employeeConverter}">
<f:selectItems value="#{empMB.employeeList}" var="emp" itemLabel="#{emp.employeeName}" itemValue="#{emp.employeeNumber}"/>
<p:ajax update="department" listener="#{empMB.onEmployeeSelect}" process="#this"/>
</p:selectOneMenu>
<p:selectOneMenu id="department" value="#{deptMB.department}" converter="#{departmentConverter}">
<f:selectItems value="#{empMB.departmentList}" var="dept" itemLabel="#{dept.departmentName}" itemValue="#{dept.departmentCode}"/>
</p:selectOneMenu>
Snippet for the bean:
public class EmpMB{
...
private List<Department> departmentList;
private Employee employee;
public List getDepartmentList(){
return departmentList;
}
public void onEmployeeSelect(){
departmentList = someService.getDepartmentsForEmployee(employee);
}
...
}
Converter sample (note that it's a spring component so that I can inject my service layer into it, but you don't HAVE to do it this way):
#Component("employeeConverter")
public class EmployeeConverter implements Converter {
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) {
//TODO: implement this
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
//TODO: implement this
}
}
I'm fairly new to Java EE and I'm building a simple webshop using maven web application . I have a problem with my Stateful Session Bean. I've been searching the net and tried different sollutions(most of them for using servlets) but it doesn't seem to work.
Anyway, my problem is that I'm trying to use my session bean to keep track of what's in the shopping cart. I am using an arrayList to store the items. However, when I add a new item it just replaces the old item instead of adding it to the list. I'm guessing the session bean somehow updates or a new instance of it is created but I just can't seem to find any sollution or information about this.
The stateful session bean
#Stateful
#LocalBean
public class CartSessionBean{
private List contents;
public CartSessionBean(){
contents= new ArrayList();
}
public List getContents() {
return contents;
}
public void addProduct(String title) {
contents.add(title);
}
}
The Managed Bean
#ManagedBean
#RequestScoped
public class ProductController {
private List cartList = new ArrayList();
private int nrOfCartItems=0;
#EJB private CartSessionBean cart;
public String doAddCart(String title)
{
cart.addProduct(title);
setCartList(cart.getContents());
setNrOfCartItems(cart.getContents().size());
return "products.xhtml";
}
}
The Facelet
<h:form>
<p>
your cart contains <h:outputLabel class="" value="#{productController.nrOfCartItems}" /> items.
<ui:repeat value="#{productController.cartList}" var="cart">
<h:outputLabel value="#{cart}" />
</ui:repeat>
<h:commandButton value="go to checkout"/>
</p>
</h:form>
<h:form>
<h:dataTable value="#{productController.productList}" var="pr" border="0">
<h:column>
<h:graphicImage value="images/#{pr.picture}" />
</h:column>
<h:column>
<h2><h:outputText value="#{pr.product_name}"/></h2>
<p> in stock: <h:outputText value="#{pr.stock}"/><br/>
price: <h:outputText value="#{pr.price}"/> SEK<br/><br/>
<h:outputText value="#{pr.description}"/><br/></p>
<h:commandButton value="add to cart" action="#{productController.doAddCart(pr.product_name)}"/>
</h:column>
</h:dataTable>
</h:form>
Your managed bean should be SessionScope to live during the session.
In your case you always creating new ProductController bean for each request and because of that you always inject different CartSessionBean (there is no way how could container know that it should inject the same SessionBean into your RequestScope Managed Bean).
This question already has an answer here:
Using <h:dataTable><h:inputText> on a List<String> doesn't update model values
(1 answer)
Closed 6 years ago.
I have jsf page:
....
<form jsfc="h:form" action="">
<h:dataTable value="#{newMusician.strings}" var="preferredMusicGenre" id="musicGenresSelectTable">
<h:column>
<h:inputText value="#{preferredMusicGenre}" immediate="true"/>
</h:column>
</h:dataTable>
<p>
<input type="submit" jsfc="h:commandButton" value="Add" action="#{newMusician.saveNewMusician}"/>
</p>
</form>
....
And managed bean that has ArrayList of Strings:
#ManagedBean
#ViewScoped
public class NewMusician {
private ArrayList<String> strings = new ArrayList<String>();
public NewMusician() {
strings.add("olo");
}
public ArrayList<String> getStrings() {
return strings;
}
public void saveNewMusician() {
.....
}
....
}
Problem: When I change text in and press save button, in saveNewMusician() method I can see that ArrayList "strings" contain the same old value "olo", but not that one I inserted in input field.
The same problem if use h:selecOneMenu.
Situation is changed if use not string, but object that aggregate string and set value into string.
So if I'll use some POJO and change inputText to:
<h:inputText value="#{preferredMusicGenrePojo.string}" immediate="true"/>
Everything becomes Ok.
Question:
Why usage of 1 level getter <h:inputText value="#{preferredMusicGenre}"/> is incorrect, but usage of 2 level getter: <h:inputText value="#{preferredMusicGenrePojo.text}"/> is Ok?
A String is immutable. It doesn't have a setter for the value. You need to wrap this around in a bean (or POJO as you call it).
public class Musician {
private String preferredGenre;
// Add/generate constructor, getter, setter, etc.
}
Then change your managed bean as follows.
#ManagedBean
#ViewScoped
public class NewMusician {
private ArrayList<Musician> musicians = new ArrayList<Musician>();
public NewMusician() {
musicians.add(new Musician("olo"));
}
public ArrayList<Musician> getMusicians() {
return musicians;
}
public void saveNewMusician() {
// ...
}
// ...
}
And your datatable:
<h:dataTable value="#{newMusician.musicians}" var="musician">
<h:column>
<h:inputText value="#{musician.preferredGenre}" />
</h:column>
</h:dataTable>