【问题标题】:p:ajax immediate="true" on UIInput does not skip validationUIInput 上的 p:ajax immediate="true" 不会跳过验证
【发布时间】:2015-03-17 20:41:55
【问题描述】:

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>

一切正常,除了&lt;p:ajax immediate="true" process="@form" update="@form" /&gt; 的行为不像UICommands 那样:验证发生(但在APPLY_REQUEST_VALUES 阶段)。

我试图挖掘 JSF 源代码并注意到 UICommands 调用 facesContext.renderResponse() 默认为 ActionListenerImpl.processAction(),所以我尝试了:

&lt;p:ajax listener="#{facesContext.renderResponse}" immediate="true" process="@form" update="@form" /&gt;

现在,当我选择“日期”时,会跳过验证,但不会更新 &lt;h:panelGroup id="detail"&gt;

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

&lt;p:ajax listener="#{immediateTestBean.skip}" immediate="true" process="@form" update="@form" /&gt;

终于成功了。

但是出现了两个问题:

  1. 为什么这么复杂?
  2. 是否有更简单的方法来实现相同的行为?

但是,这里是 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;
    }
}

【问题讨论】:

  • 我将不胜感激对否决票的解释...

标签: ajax jsf jsf-2 lifecycle


【解决方案1】:
  1. 为什么这么复杂?

根据 PrimeFaces 文档:“此功能简单但功能强大,可以进行组验证,避免验证不需要的 组件”。

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

一章中找到部分处理示例

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

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

【讨论】:

  • 我不是在谈论只是常规的部分处理或部分渲染。仔细阅读:当&lt;p:ajax immediate="true" 应用于不扩展UICommand 的组件时,会发生验证。也许尝试这个 PoC 比解释问题更容易......
【解决方案2】:

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

只需使用OmniFaces SkipValidators

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-02
    • 1970-01-01
    • 1970-01-01
    • 2011-11-10
    • 1970-01-01
    相关资源
    最近更新 更多