如何将PF依赖下拉列表转换为自动完成功能?

时间:2018-10-22 13:06:45

标签: primefaces

我已经花了很多时间试图实现与Showcase > Dependent Dropdowns所示的功能相同,但是我要使用autoComplete而不是下拉菜单(p:selectOneMenu)。

我变得有点复杂,因为我发现它并不那么简单-而不是“在页面中”,我试图在对话框中实现相同目的+我希望在未选择国家/地区时禁用城市自动完成功能。 / p>

因此最初的简单方法如下:

页面

<?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();
    }

}

这似乎是一见钟情:

  • 选择国家/地区后,将启用城市自动填充
  • 必填字段已通过验证
  • 验证没有错误时,将显示预期消息

但是

  • 当未选择国家/地区时,它不起作用(我的意思是再次禁用了城市自动完成功能)
  • 验证错误后关闭对话框时,重新打开时,将显示旧数据,并且验证后显示红色边框(尽管showDialog()中的国家和城市设置为null

我尝试通过添加以下内容来解决使用JavaScript的删除问题:

<p:ajax process="@this"
    oncomplete="if ( PF('country').input.val() == '' ) { PF('city').input.val(''); PF('city').hinput.val(''); PF('city').disable(); }" 
    update="city" />

但是它只是删除city autoComplete,但是在提交时并未被验证为丢失=不会传播到bean ...

1 个答案:

答案 0 :(得分:0)

根据我的测试,在PF版本6.2中,仅当用户从autoComplete中删除过滤器/选定的值时,才会在autoComplete上生成onchange事件。

我用它来解决它:

页面

<?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>

    <p:growl id="msgs" showDetail="true" />

    <h:form>
        <p:commandButton value="Open dialog" id="show" actionListener="#{dependentAutocompletesDialogChangeView.showDialog}" icon="ui-icon-info" update="dialog" />
    </h:form>

    <p:dialog id="dialog" widgetVar="dialog" modal="true" dynamic="true" >
        <p:ajax event="close" listener="#{dependentAutocompletesDialogChangeView.handleClose}" update="@this" resetValues="true" />
        <h:form id="form">

            <p:remoteCommand name="clearCountry" actionListener="#{dependentAutocompletesDialogChangeView.clearCountryAndCity}" immediate="true" update="city" />

            <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" widgetVar="country" value="#{dependentAutocompletesDialogChangeView.country}"
                        completeMethod="#{dependentAutocompletesDialogChangeView.countriesComplete}" process="@this" 
                        dropdown="true" required="true" emptyMessage="No countries matching filter" onchange="clearCountry()">

                        <p:ajax event="itemSelect" update="city" />

                    </p:autoComplete>

                    <p:outputLabel for="city" value="City: " />
                    <p:autoComplete id="city" value="#{dependentAutocompletesDialogChangeView.city}" 
                        completeMethod="#{dependentAutocompletesDialogChangeView.citiesComplete(dependentAutocompletesDialogChangeView.country)}"
                        dropdown="true" widgetVar="city" required="true" disabled="#{dependentAutocompletesDialogChangeView.country == null}">
                    </p:autoComplete>
                </h:panelGrid>
            </p:panel>

            <p:commandButton value="Submit" id="submit" actionListener="#{dependentAutocompletesDialogChangeView.dialogSubmit}" icon="ui-icon-check" process="dialog" update="form, msgs" />
        </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 java.util.stream.Collectors;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.view.ViewScoped;
import javax.inject.Named;

import org.primefaces.PrimeFaces;
import org.primefaces.context.RequestContext;
import org.primefaces.event.CloseEvent;

@Named
@ViewScoped
public class DependentAutocompletesDialogChangeView {


    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.stream().filter(item -> match(item, filter)).collect(Collectors.<String>toList());
    }

    private boolean match(String item, String filter) {
        return item.contains(filter);
    }

    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 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();
    }

    public void clearCountryAndCity() {
        country = null;
        city = null;

        PrimeFaces.current().executeScript("PF('country').input.val('')");
        PrimeFaces.current().executeScript("PF('city').input.val('')");
        PrimeFaces.current().ajax().update("country", "city");
    }

    public void handleClose(CloseEvent event) {
        clearCountryAndCity();
    }
}