发生验证错误后如何使用 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 填充文本字段? 的相关文章

  • 来自控制器的 Rails 验证

    有一个联系页面 可以输入姓名 电话 电子邮件和消息 然后发送到管理员的电子邮件 没有理由将消息存储在数据库中 问题 如何 在控制器中使用 Rails 验证 根本不使用模型 或者 在模型中使用验证 但没有任何数据库关系 UPD Model c
  • 数据表中每一行的工具提示

    这个问题尖叫着是重复的JSF 2 0 Primefaces 2 x 数据表行的工具提示 https stackoverflow com questions 9980155 jsf 2 0 primefaces 2 x tooltip for
  • CckEditor - 从 AJAX 加载的模板

    我正在使用 CkEditor 并且想要定义一个自定义模板 该模板使用 AJAX 函数来加载 HTML 字符串 我已经能够定义自定义模板 但如果我对模板对象的 html 属性使用函数 则该函数永远不会执行 是否可以使用 AJAX 和默认模板插
  • 自定义 jQuery 验证 .addMethod

    我有一个表单 可以根据最小 最大长度验证邮政编码 我需要将所有国家 地区的邮政编码最小设置为 5 位数字 澳大利亚除外 澳大利亚需要为 4 位数字 这是我遇到的问题 validator addMethod AusZip function v
  • JQuery:将 FormData 和 csrf 令牌一起发布

    Is the data 下面的行正确吗 我想将表单数据和 csrf 令牌发布到 Django 视图函数 file upload on change function var currentpath window location pathn
  • 如何在 CakePHP 中“验证”人名?

    我有一个 PHP 脚本 应该检查 有效 的人名 但最近破解了带有空格的名称 因此我们向验证器添加了空格 除了这样做之外 有没有办法向 CakePHP 的验证器添加黑名单以阻止所有 无效 字符 而不是允许 有效 字符 注意 我 通常 知道如何
  • 回到使用 ajax 的 PushState 条目

    我对以下情况有疑问 用户访问网站 用户点击使用history pushState的链接来更新url 通过ajax加载部分页面内容 使用jQuery 用户单击加载新页面的常规链接 用户点击返回返回到pushState条目 该页面现在仅显示通过
  • 将 JSON 发布到 Python CGI

    我已经安装了 Apache2 并且 Python 可以工作 但我有一个问题 我有两页 一个是 Python 页面 另一个是带有 JQuery 的 Html 页面 有人可以告诉我如何让我的 ajax 帖子正常工作吗
  • 如何使用 jQuery Ajax 将 PHP 数组值传递到另一个文件?

    这是我的代码
  • jQuery / Ajax:如何循环遍历数组作为 Ajax 成功函数的一部分

    我有一个阿贾克斯调用返回一个数组并需要对该数组中的每个值执行某些操作 到目前为止 我有以下内容 但这会返回以下错误 Uncaught TypeError Cannot use in operator to search for length
  • 如何取消 AjaxForm 上的提交

    我正在使用 jQuery 插件 ajax 形式 我尝试实现这样的东西 MyFormID ajaxForm dataType json resetForm true beforeSubmit function validateData ret
  • 仅当表单已提交时才触发 jQuery 表单验证?

    不引人注目的验证基于这样的想法 don t进行表单验证 直到用户提交表单 一旦发生这种情况 如果表单上的某些内容无效 那么一旦用户更改了每个字段 就会立即验证它 我想做的是 不显眼地 触发表单元素的验证 也就是说 only如果用户已尝试提交
  • 显示异常时的自定义错误消息:从客户端检测到潜在危险的 Request.Form 值

    我在我的 Web 应用程序中使用 ASP NET 的登录控件 当发生此异常时 我想在标签上显示一种有趣的错误类型System Web HttpRequestValidationException A potentially dangerou
  • 如何使用 jquery ajax 将锚点的值发送到 php

    我正在尝试使用 jquery 将几个锚点的值发送到 php 文件 但我没有从 php 脚本中得到回调 div class result div a href value class star Star 5 a a href value cl
  • 是否可以禁用特定 jQuery Ajax 调用的 Turbolinks 以防止页面刷新和滚动?

    我有一个 Rails 5 应用程序 非常想使用 Turbolinks 在应用程序中 有几个 PATCH ajax 调用 它们只是用新数据更新服务器 但不需要担心更新页面的状态 每当这些 ajax 请求返回时 Turbolinks 就会刷新页
  • OpenFaces JSF 2 组件库

    有没有人尝试过开放面孔 3 http openfaces org并可以对以下内容进行简短评论 稳定 与其他库的兼容性 PrimeFaces RichFaces 等 使用方便 换肤功能 主题支持等 我正在寻找 JSF 2 组件库 我目前正在使
  • 验证属性被触发两次

    在我的 MVC3 应用程序中 我有模型 未删除重要属性 public class AccountViewModel StringLength 65 public string Property1 get set StringLength 6
  • 客户端应用程序立即对数据库中的更新做出反应的最佳方式是什么?

    对数据库中的数据更新做出立即反应的最佳方法是什么 我能立即想到的最简单的方法是一个线程 它检查数据库中某些数据的特定更改 并持续等待在某个预定义的时间长度内再次检查它 这个解决方案对我来说似乎是浪费和次优的 所以我想知道是否有更好的方法 我
  • 我可以使用 jQuery 动态创建文件(及其内容)吗? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 这是我的 HTML 代码 ul li
  • RichFaces 应用程序,我应该使用 rich:dataTable 还是 jQGrid,优缺点吗?

    继从here https stackoverflow com questions 3899649 ok to wrap jsf components generated html with own divs using jquery aft

随机推荐