发生验证错误后如何使用 PrimeFaces AJAX 填充文本字段?

2023-12-25

我在视图中有一个表单,它执行自动完成和 gmap 本地化的 ajax 部分处理。我的支持 bean 实例化一个实体对象“Address”,并且表单的输入被引用到该对象:

@ManagedBean(name="mybean")
@SessionScoped
public class Mybean implements Serializable {
    private Address address;
    private String fullAddress;
    private String center = "0,0";
    ....

    public mybean() {
        address = new Address();
    }
    ...
   public void handleAddressChange() {
      String c = "";
      c = (address.getAddressLine1() != null) { c += address.getAddressLine1(); }
      c = (address.getAddressLine2() != null) { c += ", " + address.getAddressLine2(); }
      c = (address.getCity() != null) { c += ", " + address.getCity(); }
      c = (address.getState() != null) { c += ", " + address.getState(); }
      fullAddress = c;
      addMessage(new FacesMessage(FacesMessage.SEVERITY_INFO, "Full Address", fullAddress));
      try {
            geocodeAddress(fullAddress);
        } catch (MalformedURLException ex) {
            Logger.getLogger(Mybean.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(Mybean.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Mybean.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(Mybean.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SAXException ex) {
            Logger.getLogger(Mybean.class.getName()).log(Level.SEVERE, null, ex);
        } catch (XPathExpressionException ex) {
            Logger.getLogger(Mybean.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void geocodeAddress(String address)
            throws MalformedURLException, UnsupportedEncodingException,
            IOException, ParserConfigurationException, SAXException,
            XPathExpressionException {

        // prepare a URL to the geocoder
        address = Normalizer.normalize(address, Normalizer.Form.NFD);
        address = address.replaceAll("[^\\p{ASCII}]", "");

        URL url = new URL(GEOCODER_REQUEST_PREFIX_FOR_XML + "?address="
                + URLEncoder.encode(address, "UTF-8") + "&sensor=false");

        // prepare an HTTP connection to the geocoder
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        Document geocoderResultDocument = null;

        try {
            // open the connection and get results as InputSource.
            conn.connect();
            InputSource geocoderResultInputSource = new InputSource(conn.getInputStream());

            // read result and parse into XML Document
            geocoderResultDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(geocoderResultInputSource);
        } finally {
            conn.disconnect();
        }

        // prepare XPath
        XPath xpath = XPathFactory.newInstance().newXPath();

        // extract the result
        NodeList resultNodeList = null;

        // c) extract the coordinates of the first result
        resultNodeList = (NodeList) xpath.evaluate(
                "/GeocodeResponse/result[1]/geometry/location/*",
                geocoderResultDocument, XPathConstants.NODESET);
        String lat = "";
        String lng = "";
        for (int i = 0; i < resultNodeList.getLength(); ++i) {
            Node node = resultNodeList.item(i);
            if ("lat".equals(node.getNodeName())) {
                lat = node.getTextContent();
            }
            if ("lng".equals(node.getNodeName())) {
                lng = node.getTextContent();
            }
        }
        center = lat + "," + lng;
    }

在我提交处理整个表单之前,自动完成和地图 ajax 请求工作正常。如果验证失败,除了 fullAddress 字段无法在视图中更新之外,ajax 仍然可以正常工作,即使在 ajax 请求之后在支持 bean 上正确设置了它的值。

<h:outputLabel for="address1" value="#{label.addressLine1}"/>
<p:inputText required="true" id="address1" 
          value="#{mybean.address.addressLine1}">
  <p:ajax update="latLng,fullAddress" 
          listener="#{mybean.handleAddressChange}" 
          process="@this"/>
</p:inputText>
<p:message for="address1"/>

<h:outputLabel for="address2" value="#{label.addressLine2}"/>
<p:inputText id="address2" 
          value="#{mybean.address.addressLine2}" 
          label="#{label.addressLine2}">
  <f:validateBean disabled="#{true}" />
  <p:ajax update="latLng,fullAddress" 
          listener="#{mybean.handleAddressChange}" 
          process="address1,@this"/>
</p:inputText>
<p:message for="address2"/>

<h:outputLabel for="city" value="#{label.city}"/>
<p:inputText required="true" 
          id="city" value="#{mybean.address.city}" 
          label="#{label.city}">
  <p:ajax update="latLng,fullAddress" 
          listener="#{mybean.handleAddressChange}" 
          process="address1,address2,@this"/>
</p:inputText>
<p:message for="city"/>

<h:outputLabel for="state" value="#{label.state}"/>
<p:autoComplete id="state" value="#{mybean.address.state}" 
          completeMethod="#{mybean.completeState}" 
          selectListener="#{mybean.handleStateSelect}"
          onSelectUpdate="latLng,fullAddress,growl" 
          required="true">
  <p:ajax process="address1,address2,city,@this"/>
</p:autoComplete>
<p:message for="state"/> 

<h:outputLabel for="fullAddress" value="#{label.fullAddress}"/>
<p:inputText id="fullAddress" value="#{mybean.fullAddress}" 
          style="width: 300px;"
          label="#{label.fullAddress}"/>
<p:commandButton value="#{label.locate}" process="@this,fullAddress"
          update="growl,latLng" 
          actionListener="#{mybean.findOnMap}" 
          id="findOnMap"/>

<p:gmap id="latLng" center="#{mybean.center}" zoom="18" 
          type="ROADMAP" 
          style="width:600px;height:400px;margin-bottom:10px;" 
          model="#{mybean.mapModel}" 
          onPointClick="handlePointClick(event);" 
          pointSelectListener="#{mybean.onPointSelect}" 
          onPointSelectUpdate="growl" 
          draggable="true" 
          markerDragListener="#{mybean.onMarkerDrag}" 
          onMarkerDragUpdate="growl" widgetVar="map"/>
<p:commandButton id="register" value="#{label.register}" 
          action="#{mybean.register}" ajax="false"/>

如果我刷新页面,验证错误消息就会消失,并且 ajax 按预期完成 fullAddress 字段。

在验证期间也会出现另一个奇怪的行为:我已禁用表单字段的 bean 验证,如代码所示。在发现其他验证错误之前,此操作正常,然后,如果我重新提交表单,JSF 会对该字段进行 bean 验证!

我想我在验证状态期间遗漏了一些东西,但我无法弄清楚它出了什么问题。有谁知道如何调试 JSF 生命周期?有任何想法吗?


通过考虑以下事实可以理解问题的原因:

  • 当 JSF 在验证阶段对特定输入组件验证成功时,提交的值将设置为null并将验证后的值设置为输入组件的本地值。

  • 当 JSF 在验证阶段对特定输入组件进行验证失败时,提交的值将保留在输入组件中。

  • 当验证阶段后至少有一个输入组件无效时,JSF 将不会更新任何输入组件的模型值。 JSF 将直接进入渲染响应阶段。

  • 当JSF渲染输入组件时,它会首先测试提交的值是否不是null然后显示它,否则如果本地值不是null然后显示它,否则显示型号值。

  • 只要您与相同的 JSF 视图交互,您就会处理相同的组件状态。

因此,当特定表单提交的验证失败并且您恰好需要通过不同的 ajax 操作甚至不同的 ajax 表单来更新输入字段的值时(例如,根据下拉选择或某些操作的结果填充字段)模式对话框表单等),那么您基本上需要重置目标输入组件,以便 JSF 显示在调用操作期间编辑的模型值。否则,JSF 仍将显示验证失败期间的本地值,并使它们保持无效状态。

方法之一是在你的具体情况是手动收集要更新/重新渲染的输入组件的所有IDPartialViewContext#getRenderIds() http://docs.oracle.com/javaee/6/api/javax/faces/context/PartialViewContext.html#getRenderIds%28%29然后手动重置其状态并提交值EditableValueHolder#resetValue() http://docs.oracle.com/javaee/6/api/javax/faces/component/EditableValueHolder.html#resetValue%28%29.

FacesContext facesContext = FacesContext.getCurrentInstance();
PartialViewContext partialViewContext = facesContext.getPartialViewContext();
Collection<String> renderIds = partialViewContext.getRenderIds();

for (String renderId : renderIds) {
    UIComponent component = viewRoot.findComponent(renderId);
    EditableValueHolder input = (EditableValueHolder) component;
    input.resetValue();
}

你可以在里面做这个handleAddressChange()侦听器方法,或在可重用的内部ActionListener http://docs.oracle.com/javaee/6/api/javax/faces/event/ActionListener.html您附加的实现<f:actionListener> http://docs.oracle.com/javaee/6/javaserverfaces/2.1/docs/vdldocs/facelets/f/actionListener.html到正在调用的输入组件handleAddressChange()监听器方法。


回到具体问题,我认为这是 JSF2 规范中的一个疏忽。当 JSF 规范规定以下内容时,这对我们 JSF 开发人员来说更有意义:

  • 当 JSF 需要通过 ajax 请求更新/重新呈现输入组件,并且该输入组件未包含在 ajax 请求的处理/执行中时,JSF 应该重置输入组件的值。

这已被报道为JSF 问题 1060 http://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-1060并且已经实施了完整且可重用的解决方案OmniFaces http://omnifaces.org图书馆作为ResetInputAjaxActionListener http://omnifaces.org/docs/javadoc/current/org/omnifaces/eventlistener/ResetInputAjaxActionListener.html(源代码here https://github.com/omnifaces/omnifaces/blob/master/src/main/java/org/omnifaces/eventlistener/ResetInputAjaxActionListener.java并展示演示here http://showcase.omnifaces.org/eventlisteners/ResetInputAjaxActionListener).

更新1:从3.4版本开始,PrimeFaces基于这个想法还推出了一个完整的、可重用的解决方案<p:resetInput> http://www.primefaces.org/showcase/ui/misc/resetInput.xhtml.

更新2:从 4.0 版本开始,<p:ajax> http://www.primefaces.org/docs/vdl/4.0/primefaces-p/ajax.html得到一个新的布尔属性resetValues这也应该可以解决此类问题,而不需要额外的标签。

更新3:JSF 2.2 介绍<f:ajax resetValues> https://docs.oracle.com/javaee/7/javaserver-faces-2-2/vdldocs-facelets/f/ajax.html,遵循相同的想法<p:ajax resetValues>。该解决方案现在是标准 JSF API 的一部分。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

发生验证错误后如何使用 PrimeFaces AJAX 填充文本字段? 的相关文章

  • Primefaces 进度条动态标签

    您好 我正在使用 JSF 和 Primefaces 我有一个很长的任务 在此期间我想向用户显示一个进度条 以进度 int 和状态 String 作为指示器 这两个参数映射到后端 bean 的两个字段 如果我使用
  • 使用注释和 IValidatableObject 进行递归验证

    我正在尝试使用注释和一些自定义代码来验证嵌套对象 不是 MVC 中的模型 我发现以下帖子很有用 手动使用数据注释验证和对象图 https stackoverflow com questions 6938877 using data anno
  • Groovy:验证 JSON 字符串

    我需要检查 Groovy 中的字符串是否为有效的 JSON 我的第一个想法就是把它发送出去new JsonSlurper parseText myString 并且 如果没有例外 就假设它是正确的 然而 我发现 Groovy 很乐意接受尾随
  • onchange 使用 radioChoice 获取当前值

    我尝试使用 radioChoice onChange 从无线电表单中获取选定的值 但似乎无法真正找到解决方案 onEvent 函数被调用 但从这里我不太确定如何获取该值 Code RadioChoice
  • Django 星级评定系统和 AJAX

    我正在尝试在 Django 网站上实现星级评级系统 在我的模型中存储评级是排序的 就像在页面上显示分数一样 但我希望用户能够对页面进行评分 基本上从 1 到 5 而无需刷新或更改页面 我发现了以下内容 并且喜欢这里明星的风格 http jv
  • jquery ajax错误回调

    我在这里需要一些建议或者一些解释 我有一个 jquery ajax 调用 ajax type GET url base url ajax fetch counts dataType json data error function xhr
  • 为什么我收到此错误:“未捕获类型错误:无法读取未定义的属性“标题””?

    我正在尝试写一个ajax网络应用程序 我有一个函数应该请求一个json对象 然后使用它来重新 填充网站 这里是JavaScript有问题 第 8 16 行 window onload LoadData Home var doc functi
  • jsf中的会话注销问题

    我正在开发一个 Web 应用程序 并使用框架 jsf hibernate 和 spring 应用程序中有不同类型的用户 根据此处登录的用户类型 我为不同的用户类型启用菜单中的链接 用户登录后 会向用户提供菜单栏中的注销链接 我已经编写了 l
  • 在 Chrome/Safari 中添加 html5 属性后 Ajax 表单中断

    分步说明 新建 Asp Net MVC2 项目 Model public class TestModel public int Property get set 家庭控制器 HandleError public class HomeCont
  • 如何向 JSF 应用程序发送手动 jQuery Ajax 请求?

    我正在做一个POST 使用 jQuery 的请求似乎成功了 但是我如何在服务器端使用它并修改响应 我是否需要另一个 servlet 因为 Faces Servlet 不是为处理这个问题而设计的 ajax type POST data sta
  • “通用”电话号码的基本正则表达式

    我需要一个正则表达式 用于 ASP NET 网站 来验证电话号码 它应该是灵活的 唯一的限制是 应至少为 9 位数字 没有字母 可以包含空格 连字符 单个 我搜索过 SO 和 Regexlib com 但我得到的表达式有更多限制 例如英国电
  • JSF 的最佳实践是什么? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 未捕获的类型错误:无法读取未定义的属性“toLowerCase”

    我收到此错误 它源自 jquery 框架 当我尝试加载准备好的文档上的选择列表时 出现此错误 我似乎无法找到为什么会出现此错误 它适用于更改事件 但在尝试手动执行该函数时出现错误 未捕获的类型错误 无法读取未定义的属性 toLowerCas
  • 使用 Minitest 测试自定义验证器

    我有多个带有电子邮件验证的模型 因此 我将验证提取到自定义验证器中 我按照以下教程做到了这一点导轨指南 http guides rubyonrails org active record validations html custom va
  • Ajax JSON 数据和灯箱冲突

    我有一个带有灯箱插件的画廊设置光廊 http sachinchoolur github io lightGallery docs 该画廊与静态 HTML 完美配合 当我动态抓取 API 数据并尝试让灯箱处理这些项目时 问题就出现了 我似乎无
  • 将多个对象传递给我的控制器

    我将一个对象传递给我的控制器 如下所示 var form JSON stringify subRevisedRequest frmRevised val subSubcontractor frmSubcontractor val subDe
  • Play Framework 2.3 (Scala) 中的自定义 JSON 验证约束

    我设法使用自定义约束实现表单验证 但现在我想对 JSON 数据执行相同的操作 如何将自定义验证规则应用于 JSON 解析器 示例 客户端的 POST 请求包含用户名 username 我不仅要确保该参数是非空文本 而且还要确保该用户确实存在
  • CORS 在 jquery 中工作正常,但在 angularjs 中不行

    我的服务器端是php mysql 我正在另一个域的 Web 服务中进行 Ajax 调用 其中启用了 的访问控制 var postUrl http logical brains com elance clone test login php
  • 第三个下拉菜单不从数据库填充

    我有以下 Index php
  • 从 HTTP 登录到 HTTPS

    我的网站默认使用 HTTP 我确实有一个启用 HTTPS 的证书 但只有其上的某些区域强制建立安全连接 登录是通过 Ajax 处理的 我想开始使用 SSL 即使请求来自 HTTP 我尝试强制请求的地址具有 HTTPS 并且它完美地回复 然而

随机推荐