I spent a lot of time already trying to achieve same functionality as shown in Showcase > Dependent Dropdowns, but instead of dropdown (p:selectOneMenu
) I want to use autoComplete.
I made a bit more complex as I found it is not as simple - instead of "in page" I'm trying to achieve the same in dialog + I want city autoComplete to be disabled when there is no country selected.
So initial simple approach looks like:
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:f="http://xmlns.jcp.org/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui"
xmlns:sec="http://www.springframework.org/security/tags" xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
</h:head>
<h:body>
<h:form>
<p:commandButton value="Open dialog" id="show" actionListener="#{dependentAutocompletesDialogView.showDialog}" icon="ui-icon-info" update="dialog" />
</h:form>
<p:dialog id="dialog" widgetVar="dialog" modal="true" dynamic="true" >
<h:form prependId="false" id="form">
<p:panel header="Select a Location" style="margin-bottom:10px;">
<h:panelGrid columns="2" cellpadding="5">
<p:outputLabel for="country" value="Country: " />
<p:autoComplete id="country" value="#{dependentAutocompletesDialogView.country}" completeMethod="#{dependentAutocompletesDialogView.countriesComplete}"
dropdown="true" required="true">
<p:ajax event="itemSelect" update="city" />
</p:autoComplete>
<p:outputLabel for="city" value="City: " />
<p:autoComplete id="city" value="#{dependentAutocompletesDialogView.city}"
completeMethod="#{dependentAutocompletesDialogView.citiesComplete(dependentAutocompletesDialogView.country)}"
dropdown="true" widgetVar="city" required="true" disabled="#{dependentAutocompletesDialogView.country == null}">
</p:autoComplete>
</h:panelGrid>
</p:panel>
<p:commandButton value="Submit" id="submit" actionListener="#{dependentAutocompletesDialogView.dialogSubmit}" icon="ui-icon-check" process="dialog" update="form"/>
</h:form>
</p:dialog>
</h:body>
</html>
Bean
package com.codenotfound.primefaces.model;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
import org.primefaces.PrimeFaces;
import org.primefaces.context.RequestContext;
@Named
@ViewScoped
public class DependentAutocompletesDialogView {
private Map<String,List<String>> data = new HashMap<String, List<String>>();
private String country;
private String city;
private List<String> countries;
private List<String> cities;
public List<String> countriesComplete(String filter) {
return countries;
}
public List<String> citiesComplete(String filter) {
return data.get(country);
}
@PostConstruct
public void init() {
countries = new LinkedList<>();
countries.add("USA");
countries.add("Germany");
countries.add("Brazil");
List<String> list;
list = new LinkedList<>();
list.add("New York");
list.add("San Francisco");
list.add("Denver");
data.put("USA", list);
list = new LinkedList<>();
list.add("Berlin");
list.add("Munich");
list.add("Frankfurt");
data.put("Germany", list);
list = new LinkedList<>();
list.add("Sao Paolo");
list.add("Rio de Janerio");
list.add("Salvador");
data.put("Brazil", list);
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public List<String> getCountries() {
return countries;
}
public List<String> getCities() {
return cities;
}
public void displayLocation() {
FacesMessage msg;
if(city != null && country != null)
msg = new FacesMessage("Selected", city + " of " + country);
else
msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Invalid", "City is not selected.");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
public void onChange(AjaxBehaviorEvent event) {
System.out.println();
}
public void showDialog() {
country = null;
city = null;
RequestContext.getCurrentInstance().getScriptsToExecute().add("PF('dialog').show();");
PrimeFaces.current().ajax().update("form");
}
public void dialogSubmit() {
RequestContext.getCurrentInstance().getScriptsToExecute().add("PF('dialog').hide();");
displayLocation();
}
}
This seems as working on a first sight:
- when country is selected, cities autoComplete is enabled
- required fields are validated
- when there are no error from validation, expected message is shown
BUT
- it doesn't work, when country is unselected (I mean city autoComplete is not disabled again)
- when dialog is closed after validation errors, on re-open, there is old data and also red borders as shown after validation (despite country and city setting to null in
showDialog()
I tried to solve deletion using JavaScript by adding:
<p:ajax process="@this"
oncomplete="if ( PF('country').input.val() == '' ) { PF('city').input.val(''); PF('city').hinput.val(''); PF('city').disable(); }"
update="city" />
But it is just deleting city autoComplete, but on submit it is not validated as missing = it's not propagated to bean...