【问题标题】:Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes了解 PrimeFaces 进程/更新和 JSF f:ajax 执行/渲染属性
【发布时间】:2017-04-12 10:30:23
【问题描述】:

PrimeFaces p:commandXxx 组件中的 processupdate 以及 f:ajax 标签中的 executerender 到底是什么?

验证时哪个有效? update 属性做什么而不是从后端更新组件的值? process 属性是否将值绑定到模型? @this@parent@all@form 在这两个属性中到底是什么?

下面的示例运行良好,但我对基本概念有点困惑。

<p:commandButton process="@parent"
                 update="@form"
                 action="#{bean.submit}" 
                 value="Submit" />

【问题讨论】:

    标签: jsf primefaces process updates


    【解决方案1】:

    &lt;p:commandXxx process&gt;&lt;p:ajax process&gt;&lt;f:ajax execute&gt;

    process 属性是服务器端的,只能影响实现EditableValueHolder(输入字段)或ActionSource(命令字段)的UIComponents。 process 属性使用空格分隔的客户端 ID 列表告诉 JSF,在(部分)表单提交时,哪些组件必须在整个 JSF 生命周期中准确处理。

    JSF 然后将应用请求值(根据组件自己的客户端 ID 查找 HTTP 请求参数,然后在 EditableValueHolder 组件的情况下将其设置为提交的值,或者在 ActionSource 组件的情况下将新的ActionEvent 排队),执行转换、验证和更新模型值(仅限EditableValueHolder 组件),最后调用排队的ActionEvent(仅限ActionSource 组件)。 JSF 将跳过对process 属性未涵盖的所有其他组件的处理。此外,在应用请求值阶段其rendered 属性评估为false 的组件也将被跳过,以防止被篡改请求。

    请注意,在ActionSource 组件(例如&lt;p:commandButton&gt;)的情况下,将组件本身包含在process 属性中非常重要,尤其是在您打算调用与组件关联的操作时。因此,以下示例在调用某个命令组件时仅处理某些输入组件是行不通的:

    <p:inputText id="foo" value="#{bean.foo}" />
    <p:commandButton process="foo" action="#{bean.action}" />
    

    它只会处理#{bean.foo}不会处理#{bean.action}。您还需要包含命令组件本身:

    <p:inputText id="foo" value="#{bean.foo}" />
    <p:commandButton process="@this foo" action="#{bean.action}" />
    

    或者,正如您显然发现的那样,如果它们恰好是唯一具有共同父级的组件,则使用 @parent

    <p:panel><!-- Type doesn't matter, as long as it's a common parent. -->
        <p:inputText id="foo" value="#{bean.foo}" />
        <p:commandButton process="@parent" action="#{bean.action}" />
    </p:panel>
    

    或者,如果它们恰好是父UIForm组件的唯一组件,那么您也可以使用@form

    <h:form>
        <p:inputText id="foo" value="#{bean.foo}" />
        <p:commandButton process="@form" action="#{bean.action}" />
    </h:form>
    

    如果表单包含更多您想在处理过程中跳过的输入组件,这有时是不可取的,这在您想根据当前更新另一个输入组件或某些 UI 部分的情况下更常见ajax 侦听器方法中的输入组件。您不希望其他输入组件上的验证错误阻止执行 ajax 侦听器方法。

    然后是@all。这在process 属性中没有特殊效果,而仅在update 属性中。 process="@all" 的行为与 process="@form" 完全相同。 HTML 无论如何都不支持同时提交多个表单。

    顺便说一句,还有一个@none,如果您绝对不需要处理任何东西,但想通过update更新某些特定部分,特别是那些其内容不依赖于提交的值或操作侦听器的部分。

    需要注意的是process 属性对HTTP 请求负载(请求参数的数量)有没有影响。这意味着,发送包含在&lt;h:form&gt; 的 HTML 表示中的“所有内容”的默认 HTML 行为将不受影响。如果您的表单很大,并且希望将 HTTP 请求负载减少到处理中绝对必要的那些,即只有 process 属性覆盖的那些,那么您可以在 PrimeFaces Ajax 组件中设置 partialSubmit 属性,如 @ 987654376@ 或&lt;p:ajax ... partialSubmit="true"&gt;。您还可以通过编辑web.xml 并添加来“全局”配置此设置

    <context-param>
        <param-name>primefaces.SUBMIT</param-name>
        <param-value>partial</param-value>
    </context-param>
    

    或者,您也可以使用 OmniFaces 3.0+ 的 &lt;o:form&gt;,它默认为这种行为。

    等效于 PrimeFaces 特定 process 的标准 JSF 是来自 &lt;f:ajax execute&gt;execute。它的行为完全相同,只是它不支持逗号分隔的字符串,而 PrimeFaces 支持(尽管我个人建议只坚持空格分隔的约定),也不支持 @parent 关键字。此外,知道&lt;p:commandXxx process&gt; 默认为@form&lt;p:ajax process&gt;&lt;f:ajax execute&gt; 默认为@this 可能很有用。最后,知道process 支持所谓的“PrimeFaces 选择器”也很有用,另见How do PrimeFaces Selectors as in update="@(.myClass)" work?


    &lt;p:commandXxx update&gt;&lt;p:ajax update&gt;&lt;f:ajax render&gt;

    update 属性是客户端,可以影响所有UIComponents 的HTML 表示。 update 属性告诉 JavaScript(负责处理 ajax 请求/响应的),使用空格分隔的客户端 ID 列表,HTML DOM 树中的哪些部分需要更新为对表单提交的响应。

    JSF 然后会为此准备正确的 ajax 响应,其中包含 请求更新的部分。 JSF 将跳过 ajax 响应中 update 属性未涵盖的所有其他组件,从而使响应负载保持较小。此外,在渲染响应阶段其rendered 属性评估为false 的组件将被跳过。请注意,即使它会返回 true,如果它最初是 false,JavaScript 也无法在 HTML DOM 树中更新它。您需要将其包装或更新其父级。另见Ajax update/render does not work on a component which has rendered attribute

    通常,您希望更新真正需要在(部分)表单提交时在客户端“刷新”的组件。下面的例子通过@form更新整个父表单:

    <h:form>
        <p:inputText id="foo" value="#{bean.foo}" required="true" />
        <p:message id="foo_m" for="foo" />
        <p:inputText id="bar" value="#{bean.bar}" required="true" />
        <p:message id="bar_m" for="bar" />
        <p:commandButton action="#{bean.action}" update="@form" />
    </h:form>
    

    (注意process 属性被省略,因为它已经默认为@form

    虽然这可能工作正常,但在这个特定示例中,输入和命令组件的更新是不必要的。除非您在 action 方法中更改模型值 foobar(这反过来在 UX 角度来看是不直观的),否则没有必要更新它们。消息组件是唯一真正需要更新的组件:

    <h:form>
        <p:inputText id="foo" value="#{bean.foo}" required="true" />
        <p:message id="foo_m" for="foo" />
        <p:inputText id="bar" value="#{bean.bar}" required="true" />
        <p:message id="bar_m" for="bar" />
        <p:commandButton action="#{bean.action}" update="foo_m bar_m" />
    </h:form>
    

    但是,当您拥有许多此类时,这会变得乏味。这就是 PrimeFaces 选择器存在的原因之一。这些消息组件在生成的 HTML 输出中有一个通用的样式类 ui-message,因此也应该执行以下操作:

    <h:form>
        <p:inputText id="foo" value="#{bean.foo}" required="true" />
        <p:message id="foo_m" for="foo" />
        <p:inputText id="bar" value="#{bean.bar}" required="true" />
        <p:message id="bar_m" for="bar" />
        <p:commandButton action="#{bean.action}" update="@(.ui-message)" />
    </h:form>
    

    (请注意,您应该保留消息组件上的 ID,否则 @(...) 将不起作用!再次,请参阅 How do PrimeFaces Selectors as in update="@(.myClass)" work? 了解详细信息)

    @parent 仅更新父组件,从而覆盖当前组件以及所有兄弟姐妹及其子组件。如果您将表单分成不同的组并各自负责,这将更加有用。 @this 显然只更新当前组件。通常,只有当您需要在 action 方法中更改组件自己的 HTML 属性之一时,才需要这样做。例如

    <p:commandButton action="#{bean.action}" update="@this" 
        oncomplete="doSomething('#{bean.value}')" />
    

    假设oncomplete 需要与value 一起使用,而action 中已更改,那么如果不更新组件,则此构造将无法工作,原因很简单,oncomplete 是生成的 HTML 输出的一部分(因此其中的所有 EL 表达式都会在呈现响应期间进行评估)。

    @all 更新整个文档,应谨慎使用。通常,您希望通过纯链接(&lt;a&gt;&lt;h:link&gt;)或?faces-redirect=trueExternalContext#redirect() 的redirect-after-POST 对此使用真正的GET 请求。在效果上,process="@form" update="@all" 与非 ajax(非部分)提交的效果完全相同。在我的整个 JSF 职业生涯中,我遇到的关于 @all 的唯一合理用例是在 ajax 请求期间发生异常时完整显示错误页面。另见What is the correct way to deal with JSF 2.0 exceptions for AJAXified components?

    等效于 PrimeFaces 特定 update 的标准 JSF 是来自 &lt;f:ajax render&gt;render。它的行为完全相同,只是它不支持逗号分隔的字符串,而 PrimeFaces 则支持(尽管我个人建议坚持使用空格分隔的约定),也不支持 @parent 关键字。 updaterender 都默认为 @none(即“无”)。


    另请参阅:

    【讨论】:

    • 当我使用 update="" 时,后备 bean 的托管属性没有设置,我的 @PostConstruct 例程失败。有什么想法吗?编辑:•如果您依赖 #{param} 的托管属性出现在后续 POST 请求中,那么您需要将其作为
    • 可能一个panelGroup的处理/更新将处理/更新这个panelGroup的内容例如://输入文本到这里

    • 感谢@BalusC 这个非常好的解释!
    • @Rapster:因为没有设置process,所以它使用默认值@form。上面的答案也解释了这一点。
    • @Roland:它隐藏了一个不同的、更严重的应用配置问题。
    【解决方案2】:

    如果您很难记住默认值(我知道我有...),这里是 BalusC 答案的简短摘录:

    Component Submit Refresh
    f:ajax execute="@this" render="@none"
    p:ajax process="@this" update="@none"
    p:commandXXX process="@form" update="@none"

    【讨论】:

    • 只是一个小的修正:process 的默认值为p:commandXXX@all。另外,这似乎适用于所有支持 AJAX 的组件,例如 p:menuitem
    • 嗨@StephanRauh,非常感谢您的评论。你在哪里读到的默认是@all?据我所知,BalusC 的答案是@form,但是@all 相当于@form 正在处理中。关于其他组件的好点,我想我必须在源代码中查看它适用于哪些组件,因为我宁愿不写一些可能是错误的东西
    • @JaqenH'ghar Thomas Andraschko 告诉我@all 位。他一定知道,他最近重新实现了PrimeFaces的AJAX引擎。后来,我仔细检查了它,但阅读了 PrimeFaces 的源代码并查看了 XHR 请求。我希望这次我做对了,因为我已经实现了 BootsFaces 的 AJAX 请求与 PrimeFaces 的 AJAX 请求的工作方式相同。
    • 当 HTML 不支持提交多个表单时,默认为 @all 会产生误导。开发人员需要知道有效的默认值(因此 Thomas 可能会相应地更改它)。顺便说一句,这些默认值在 Primefaces 用户指南 6.2 中被错误地定义为 null。
    【解决方案3】:

    通过进程(在 JSF 规范中称为执行),您告诉 JSF 将处理限制在指定的组件上,其他所有内容都将被忽略。

    update 指示当服务器响应您的请求时将更新哪个元素。

    @all :处理/渲染每个组件。

    @this:具有执行属性的请求组件被处理/渲染。

    @form :处理/呈现包含请求组件的表单。

    @parent:处理/渲染包含请求组件的父级。

    借助 Primefaces,您甚至可以使用 JQuery 选择器,请查看此博客:http://blog.primefaces.org/?p=1867

    【讨论】:

      【解决方案4】:

      JSF 2.0+ 关键字

      • @this 当前组件。
      • @all 全景。
      • @form 当前组件的最近祖先形式。
      • @none 无组件。

      JSF 2.3+ 关键字

      • @child(n) 第 n 个孩子。
      • @composite 最近的复合组件祖先。
      • @id(id) 用于通过 id 搜索组件,忽略组件树结构和命名容器。
      • @namingcontainer 当前组件最近的祖先命名容器。
      • @parent 当前组件的父级。
      • @previous 上一个兄弟姐妹。
      • @next 下一个兄弟姐妹。
      • @root UIViewRoot 视图实例,可用于从根目录开始搜索,而不是从当前组件开始搜索。

      PrimeFaces 特定关键字

      • @row(n)第 n 行。
      • @widgetVar(name) 具有给定 widgetVar 的组件。

      你甚至可以使用一种叫做“PrimeFaces Selectors”的东西,它允许你使用 jQuery Selector API。例如,使用 CSS 类 myClass 处理元素中的所有输入:

      process="@(.myClass :input)"
      

      见:

      PrimeFaces 10+ 观察者/事件

      这允许您根据@obs(event) 关键字设置的自定义事件名称更新组件。例如:

      <p:commandButton update="@obs(myEvent)"/>
      
      <h:panelGroup>
          <p:autoUpdate on="myEvent"/>
      </h:panelGroup>
      

      见:

      【讨论】:

        猜你喜欢
        相关资源
        最近更新 更多