p:UIInput上的ajax immediate =“true”不会跳过验证

时间:2015-01-19 18:42:13

标签: ajax jsf jsf-2 lifecycle

TL; DR

<h:form>
    <p:inputText required="true">
        <p:ajax event="click" immediate="true" process="@this" update="@this" />
    </p:inputText>
</h:form>

单击导致验证,即使ajax是立即的。为什么呢?


无法使最终解决了这个问题:

<h:form>
    <p:dataGrid var="elem" value="#{immediateTestBean.elements}" columns="3">
        <f:facet name="footer">
            <p:commandButton action="#{immediateTestBean.newElement}" immediate="true"
                process="@namingcontainer" update="@namingcontainer" value="#{bundle.add}" />
        </f:facet>

        <h:panelGrid columns="3">
            <p:selectOneMenu value="#{elem.type}">
                <p:ajax immediate="true" process="@form" update="@form" />
                <f:selectItem itemValue="text" itemLabel="#{bundle.text}" />
                <f:selectItem itemValue="date" itemLabel="#{bundle.date}" />
            </p:selectOneMenu>

            <h:panelGroup id="detail">
                <p:inputText value="#{elem.text}" required="true" rendered="#{elem.type == 'text'}"
                    validator="#{immediateTestBean.testValidate}" label="#{bundle.text}">
                    <f:validateLength minimum="4" />
                </p:inputText>
                <p:calendar value="#{elem.date}" required="true" rendered="#{elem.type == 'date'}"
                    pattern="dd/MM/yyyy" readonlyInput="true" showOn="button"
                    validator="#{immediateTestBean.testValidate}" label="#{bundle.date}" />
            </h:panelGroup>

            <p:commandButton action="#{immediateTestBean.removeElement(elem)}" immediate="true"
                process="@namingcontainer" update="@namingcontainer" value="#{bundle.remove}" />
        </h:panelGrid>
    </p:dataGrid>

    <p:spacer height="10" style="display: block" />

    <p:commandButton process="@form" update="@form" value="#{bundle.submit}" />
</h:form>

一切正常,除<p:ajax immediate="true" process="@form" update="@form" />之外没有UICommand的行为:验证发生(但在APPLY_REQUEST_VALUES阶段)。

我试图深入挖掘JSF源代码并注意UICommand在默认facesContext.renderResponse()中调用ActionListenerImpl.processAction(),所以我尝试了:

<p:ajax listener="#{facesContext.renderResponse}" immediate="true" process="@form" update="@form" />

现在,当我选择&#39; date&#39;时,会跳过验证,但不会更新<h:panelGroup id="detail">

然后,我认为跳过验证也导致了更新模型的跳过,所以我打电话给:

<p:ajax listener="#{immediateTestBean.skip}" immediate="true" process="@form" update="@form" />

最后它有效。

但是出现了两个问题:

  1. 为什么这么复杂?
  2. 是否有更简单的方法来实现相同的行为?
  3. 但是,这是bean的代码:

    @ManagedBean
    @ViewScoped
    public class ImmediateTestBean implements Serializable
    {
        private static final long serialVersionUID = 1L;
    
        private static final Logger logger = LoggerFactory.getLogger(ImmediateTestBean.class);
    
        public class Element
        {
            private String type = "text";
    
            private String text;
    
            private Date date;
    
            public String getType()
            {
                return type;
            }
    
            public void setType(String type)
            {
                this.type = type;
            }
    
            public String getText()
            {
                return text;
            }
    
            public void setText(String text)
            {
                this.text = text;
            }
    
            public Date getDate()
            {
                return date;
            }
    
            public void setDate(Date date)
            {
                this.date = date;
            }
        }
    
        private final List<Element> elements = new ArrayList<>();
    
        public void testValidate(FacesContext context, UIComponent component, Object value)
        {
            logger.debug("phase: {}", context.getCurrentPhaseId());
        }
    
        public void skip()
        {
            logger.debug("Faces.getCurrentPhaseId(): {}", Faces.getCurrentPhaseId());
    
            UIInput component = (UIInput) Components.getCurrentComponent();
            logger.debug("component: {}", component);
    
            FacesContext context = Faces.getContext();
            component.validate(context);
            if(component.isValid())
            {
                component.updateModel(context);
            }
    
            Faces.renderResponse();
        }
    
        public void newElement()
        {
            elements.add(new Element());
        }
    
        public void removeElement(Element elem)
        {
            elements.remove(elem);
        }
    
        public List<Element> getElements()
        {
            return elements;
        }
    }
    

2 个答案:

答案 0 :(得分:3)

  1. 为什么这么复杂?
  2. 根据PrimeFaces文档:&#34;此功能简单但功能强大,足以执行组验证,避免验证不需要的 部件&#34;

    您可以在PrimeFaces文档的 4.2部分处理

    章节中找到部分处理的示例

    尝试使用<p:ajax immediate="true" process="@this, #{p:component('detail')}" update="#{p:component('detail')}" />

    immediate="true"将跳过流程验证,更新模型值和调用应用程序JSF生命周期阶段,但process="@this, #{p:component('detail')}"将仅为组件执行应用请求值,流程验证,更新模型值和调用应用程序JSF生命周期阶段{ {1}}和<h:panelGroup id="detail"

答案 1 :(得分:2)

缺少JSF,在每种情况下都无法使用immediate="true"进行模拟。

只需使用OmniFaces SkipValidators

即可