【问题标题】:Primefaces JSF update after validation failed doesn't work验证失败后 Primefaces JSF 更新不起作用
【发布时间】:2012-01-30 11:15:31
【问题描述】:

我在验证 <p:inputText> 和更新其内容时遇到问题。

基本上当 inputText 验证失败时,它永远不会再次更新。

这里有一个简单的例子来说明:

Facelet:

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

        <h:form id="list" prependId="false">
            <ul>
                <li>Element 1&#160;
                    <p:commandLink action="#{Test.assignElement}" update="detail_value">
                        <f:setPropertyActionListener target="#{Test.currentElement}" value="1" />
                        Assign
                    </p:commandLink>
                </li>
                <li>Element 2&#160;
                    <p:commandLink action="#{Test.assignElement}" update="detail_value">
                        <f:setPropertyActionListener target="#{Test.currentElement}" value="2" />
                        Assign
                    </p:commandLink>
                </li>
            </ul>
        </h:form>

        <h:form id="detail" prependId="false">
            <p:inputText value="#{Test.element}" id="detail_value" required="true" styleClass="#{Faces.messagesFor['detail_value'] ? 'border:1px solid red' : ''}">
                <p:ajax event="blur" update="detail_value"></p:ajax>
            </p:inputText>
        </h:form>
    </body>
</html>

测试 bean:

package com.easydevel.test;

public class Test {

    private String currentElement;
    private String element;

    public String getCurrentElement() {
        return currentElement;
    }

    public void setCurrentElement(String currentElement) {
        this.currentElement = currentElement;
    }

    public String getElement() {
        return element;
    }

    public void setElement(String element) {
        this.element = element;
    }

    public String assignElement(){
        setElement(getCurrentElement());
        return "";
    }

}

如果您单击“元素”下方的 commandLinks,则输入字段会更新,但是当验证失败时(只需将输入文本留空,然后单击页面的任何其他部分),输入的边框变红。之后,单击上述命令链接时,它就再也不会更新了。

有什么想法吗?

【问题讨论】:

    标签: validation jsf primefaces ajax-update


    【解决方案1】:

    这是臭名昭著的“输入元素”(实际上是EditableValueHolders)案例,一旦验证失败,它们就永远无法通过 AJAX 重新渲染再次更新。

    见:

    1. JSF AJAX validation: execute="@this" render="@form" inconsistent depending on prior requests
    2. How can I populate a text field using PrimeFaces AJAX after validation errors occur?
    3. http://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-1060

    一种解决方法是创建一个动作侦听器来重置要重新渲染的组件。见本页最后一页:http://community.jboss.org/message/620000

    如果这种行为让您感到困扰(我猜确实如此),那么请不要犹豫,为JAVASERVERFACES_SPEC_PUBLIC-1060 投票,如果可能的话,请留下评论,告诉您您的期望和原因。

    【讨论】:

      【解决方案2】:

      我会自己回答。

      基于 Arjan 提供的链接,我开发了 actionListener 来清理表单元素。并且有效。

      小脸:

      <p:commandLink action="#{Test.assignElement}" update="detail_value">
                             <f:actionListener type="com.easydevel.utils.CleanForms" />
                             <f:setPropertyActionListener target="#{Test.currentElement}" value="1" />
                             Assign
      </p:commandLink>    
      

      还有聆听者....

      package com.easydevel.utils;
      
      import java.util.Collection;
      import java.util.Iterator;
      import javax.faces.component.EditableValueHolder;
      import javax.faces.component.UIComponent;
      import javax.faces.context.FacesContext;
      import javax.faces.context.PartialViewContext;
      import javax.faces.event.AbortProcessingException;
      import javax.faces.event.ActionEvent;
      import javax.faces.event.ActionListener;
      
      
      public class CleanForms implements ActionListener {
      
       public void processAction(ActionEvent event) throws AbortProcessingException {                
           FacesContext facesContext = FacesContext.getCurrentInstance();
           PartialViewContext ajaxContext = facesContext.getPartialViewContext();
           UIComponent root = facesContext.getViewRoot();          
           Collection<String> renderIds = ajaxContext.getRenderIds();
           for (String renderId : renderIds) {
              UIComponent form = findComponent(root,renderId);
              if (form != null) {
                   clearComponentHierarchy(form);
              }
           }
       }
      
       private void clearComponentHierarchy(UIComponent pComponent) {
      
            if (pComponent.isRendered()) {
      
                 if (pComponent instanceof EditableValueHolder) {
                      EditableValueHolder editableValueHolder = (EditableValueHolder) pComponent;
                      editableValueHolder.setSubmittedValue(null);
                      editableValueHolder.setValue(null);
                      editableValueHolder.setLocalValueSet(false);
                      editableValueHolder.setValid(true);
                 }          
      
                 for (Iterator<UIComponent> iterator = pComponent.getFacetsAndChildren(); iterator.hasNext();) {
                      clearComponentHierarchy(iterator.next());
                 }          
      
            }
       }
      
       private static UIComponent findComponent(UIComponent base, String id) {
             if (id.equals(base.getId()))
               return base;
             UIComponent kid = null;
             UIComponent result = null;
             Iterator kids = base.getFacetsAndChildren();
             while (kids.hasNext() && (result == null)) {
               kid = (UIComponent) kids.next();
               if (id.equals(kid.getId())) {
                 result = kid;
                 break;
               }
               result = findComponent(kid, id);
               if (result != null) {
                 break;
               }
             }
             return result;
         }
      
      }
      

      【讨论】:

        【解决方案3】:

        Arjan tijms 答案会起作用,但是我发现的最佳解决方案是:

        1. 使用Omnifaces Solution 因此,您只需一行简单的代码即可,而不是实现您自己的监听器。

          <h:commandButton value="Update" action="#{bean.updateOtherInputs}">
          <f:ajax execute="currentInputs" render="otherInputs" />
          <f:actionListener type="org.omnifaces.eventlistener.ResetInputAjaxActionListener" />
          </h:commandButton>
          
        2. 如果你使用 Primefaces,你可以使用resetInput component

          <p:commandButton value="Reset Non-Ajax" actionListener="#{resetInputView.reset}"
          immediate="true" ajax="false" style="margin-right:20px;">
          <p:resetInput target="panel" />
          </p:commandButton>  
          

        【讨论】:

          猜你喜欢
          • 2013-11-25
          • 1970-01-01
          • 2016-01-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-25
          相关资源
          最近更新 更多