• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

<p:ajax listener= */> is getting invoked. Tried with f:ajax and still all in vain

 
Greenhorn
Posts: 23
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi All,

As i am new to JSF-Primefaces , I was trying to make two drop down. first is for the country and on change of the country i will list cities in the next drop down. But my p;ajax action is not getting invoked.
Please find the below code snippet :

ajaxFirst.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:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Welcome</title>
</h:head>
<h:body>
<h:form>

<h3>AJAX TEST 123</h3>
<h:outputText value="Country: " />
<h:selectOneMenu id="countries" value="#{partialProcessingController.country}">
<f:selectItems value="#{partialProcessingController.country}" />
<p:ajax listener="#{partialProcessingController.handleCountryChange}" event="valueChange" process="@this"/>
<f:attribute name="item" value="#{problem}"/>
</h:selectOneMenu>
<h:outputText value="City: " />
<h:selectOneMenu id="cities" value="#{partialProcessingController.city}">
<f:selectItems value="#{partialProcessingController.city}" />
</h:selectOneMenu>
<h:outputText value="Email: " />
<h:inputText value="#{partialProcessingController.email}"
required="true" />
</h:form>
</h:body>
</html>


Bean = "partialProcessingController"

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ValueChangeEvent;


@ManagedBean(name="partialProcessingController")
@ViewScoped
public class CountryStates implements Serializable {

private List<String> country = new ArrayList<String>();
public List<String> getCountry() {
return country;
}

public void setCountry(List<String> country) {
this.country = country;
}

public List<String> getCity() {
return city;
}

public void setCity(List<String> city) {
this.city = city;
}

private List<String> city = new ArrayList<String>();
private String email;


@PostConstruct
public void countryList(){
country.add("India");
country.add("USA");
country.add("Russia");
}

public void handleCountryChange(ValueChangeEvent event)
{
System.out.println("ppopopopopopo");
String problem = (String) event.getComponent().getAttributes().get("item");
if (problem=="India")
{
city.add("Delhi");
city.add("Agra");
city.add("J&k");
}
if (problem=="USA")
{
city.add("LA");
city.add("LV");
city.add("NY");
}
if (problem=="Russia")
{
city.add("Moscow");
city.add("NT");
city.add("listing123");
}

}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}
}



I have tried using f:ajax , still action not getting invoked. Then i tried with valueChangeListener and still the same result. Please help in this concern.


 
Saloon Keeper
Posts: 27763
196
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Some basic things just to make it easier:

1. We have a "Code" button on our message editor that can wrap code tags around pre-formatted text such as Java code or XML. You can use that to make your samples easier to read (it also preserves indentation).

2. You do not write "Controllers" in JSF. JSF's Controllers are the FacesServlet and the internal tag logic. JSF only requires you to code View Templates (.xhtml) and Models (backing beans). Don't let the extra logic in backing beans fool you. A Controller's sole function is to transfer data from the Model to the View and from the View to the model. Nothing more, nothing less. And JSF itself handles that.

OK. You've designed a simple hard-coded case of a common problem. Here's a solution that works well for me.

First and foremost, don't use raw string collections for your selectItems. Maybe JSF 2 permits it, but it's a convenience feature, since the actual sub-Model objects are instances of class SelectItem and if you depend on JSF to construct them from raw strings, you lose flexibility. For example, you may want to display "United States" in the country dropdown, but use the data value "US" in your code. A SelectItem is a Model item whose 2 attributes are the label ("United States") and the value ("US"). The single-argument constructor is a degenerate case where the label and value are always the same.

Secondly, instead of pre-initializing the submodels, do it "on demand". That is, forget the @PostConstruct. On the first invocation of getCountry(), construct the country SelectItem list and cache it in the country property. Thereafter, use the cached value so as to avoid the overhead of constructing the selectitem list multiple times per request. Do the same for the city SelectItem List.

Why do that? Because of this:



Incidentally, you're also using the same property ("city") for both the selected city value AND the city SelectItem list. That won't work. Not only are they 2 different sets of data, they're 2 different KINDS of data.

So, the corresponding sub-View is now this:



So, in sum, the magic is performed by having my SelectItemList property-get methods check for a null SelectItemList. If the list is null, the "get" method invokes "buildXXXList()", which allocates and initializes the SelectItems and returns the list of SelectItems to the "get" method, which then caches them.

The buildXXXList method is a private method whose basic function is simply what I just said, but if it's going to be loading in values from a database, I usually have it invoke a "loadXXXList()" method so as to separate the UI-related code from the persistence-related code.

Now, returning to the Big Picture. Your AJAX event method isn't firing because it has the wrong signature. An Ajax Listener - per the Oracle specs, should be in the form:


If the signature doesn't match, the method is silently ignored.

If you want to handle a valueChangeEvent, you must reference a valueChangeEventListener method on the h:selectOneMenu control itself. You still need AJAX, but you don't actually need an AJAX listener method. That's because a valueChangeListener doesn't fire when the value changes, it fires when a form is submitted and a value change was detected. So the AJAX tag forces a partial form submit, thus invoking the valueChangeListener. Since all the necessary logic is done either by the valueChangeListener itself or as a consequence of that listener in the re-rendering process of the AJAX request. That is, once the valueChangeListener resets the City list, then the "getCityList will build a new city list based on the new country value (since country will be updated by JSF's internal Controller after the valueChangeListener fires, but before the getCityList() method is invoked by the renderer).

Which brings us to the one final thing. When you code AJAX into a JSF control, by default only that control participates. But you want another control to be updated (with a new city SelectItem list) when you change the value of the Country control. So include the "render="city"" attribute on the p:ajax tag to tell AJAX to update the page with the new city selection information.

Incidentally, a side benefit of this strategy is that you can trigger a reset of the parent and dependent selection controls anytime you want just by nulling out their models and clearing their currect selections (if you don't clear the selection value, JSF will throw a validation exception, since the selection is no longer in the list). You can do this any time, not just in valueChangeListeners. Well, almost any time. Don't do it in the "get" methods or you may change data in mid-render.
reply
    Bookmark Topic Watch Topic
  • New Topic