了解PrimeFaces流程/更新和JSF f:ajax执行/渲染属性 [英] Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes

查看:165
本文介绍了了解PrimeFaces流程/更新和JSF f:ajax执行/渲染属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

下面的示例工作正常,但是我对基本概念有些困惑.

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

解决方案

<p:commandXxx process> <p:ajax process> <f:ajax execute>

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

然后,JSF将应用请求值(根据组件自己的客户端ID查找HTTP请求参数,然后在EditableValueHolder组件的情况下将其设置为已提交值,或对新的

它只会处理#{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,如果您绝对不需要处理任何东西,但是 only 想要通过update更新某些特定的部分,尤其是那些特定的部分,这可能会很有用内容不取决于提交的值或操作侦听器的部分.

请注意,process属性对HTTP请求有效负载(请求参数的数量)没有没有的影响.这意味着,发送<h:form>的HTML表示中包含的所有内容"的默认HTML行为将不会受到影响.如果您的表单很大,并且希望将HTTP请求有效负载减少到仅在处理中绝对必要的那些,即仅将这些内容覆盖在process属性中,则可以在PrimeFaces Ajax组件中将partialSubmit属性设置为<p:commandXxx ... partialSubmit="true"><p:ajax ... partialSubmit="true">.另外,您也可以使用OmniFaces 3.0+的 <o:form> (默认为这种行为).

等同于PrimeFaces特定process的标准JSF是<f:ajax execute>中的execute.它的行为完全相同,不同之处在于它不支持逗号分隔的字符串,而PrimeFaces则支持(尽管我个人建议仅使用空格分隔的约定),也不支持@parent关键字.同样,了解<p:commandXxx process>默认为@form<p:ajax process><f:ajax execute>默认为@this可能很有用.最后,知道process支持所谓的"PrimeFaces Selectors"也很有用,另请参见


<p:commandXxx update> <p:ajax update> <f:ajax render>

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

然后,JSF将为此准备正确的ajax响应,其中仅包含 所请求的要更新的部分. JSF将跳过ajax响应中未被update属性覆盖的所有其他组件,从而使响应有效载荷保持较小.同样,在渲染响应阶段,其rendered属性的值为c2的组件也将被跳过.请注意,即使最初返回false,JavaScript也无法在HTML DOM树中对其进行更新.您需要包装它或更新其父代.另请参见 Ajax更新/渲染不适用于具有渲染属性的组件.

通常,您只想 更新真正需要在(部分)表单提交时在客户端刷新"的组件.下面的示例通过@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保留在消息组件上,否则@(...)将不起作用!再次,请参见了解详情)

@parent仅更新父组件,从而覆盖了当前组件以及所有兄弟姐妹及其子代.如果您将表格分为理智的组别并各自负责,则此功能将更为有用.显然,@this仅更新当前组件.通常,仅当您需要在action方法中更改组件自己的HTML属性之一时,才需要这样做.例如

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

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

@all更新整个文档,应谨慎使用.通常,您希望为此使用真正的GET请求,而不是通过纯链接(<a><h:link>)或通过?faces-redirect=trueExternalContext#redirect()的POST后重定向.实际上,process="@form" update="@all"具有与非ajax(非部分)提交完全相同的效果.在我整个JSF生涯中,我遇到的@all唯一明智的用例是完整显示一个错误页面,以防ajax请求期间发生异常.另请参见处理AJAXified组件的JSF 2.0异常的正确方法是什么?

与PrimeFaces特定update等效的标准JSF是<f:ajax render>中的render.它的行为完全相同,不同之处在于它不支持逗号分隔的字符串,而PrimeFaces则支持(尽管我个人建议仅使用空格分隔的约定),也不支持@parent关键字. updaterender均默认为@none(即无").


另请参见:

What exactly are process and update in PrimeFaces p:commandXxx components and execute and render in f:ajax tag?

Which works at the time of validation? What does update attribute do rather than updating value to component from back end? Do process attribute bind value to model? What exactly do @this, @parent, @all and @form in both attributes?

The example below is working fine, but I am a little confused in basic concepts.

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

解决方案

<p:commandXxx process> <p:ajax process> <f:ajax execute>

The process attribute is server side and can only affect UIComponents implementing EditableValueHolder (input fields) or ActionSource (command fields). The process attribute tells JSF, using a space-separated list of client IDs, which components exactly must be processed through the entire JSF lifecycle upon (partial) form submit.

JSF will then apply the request values (finding HTTP request parameter based on component's own client ID and then either setting it as submitted value in case of EditableValueHolder components or queueing a new ActionEvent in case of ActionSource components), perform conversion, validation and updating the model values (EditableValueHolder components only) and finally invoke the queued ActionEvent (ActionSource components only). JSF will skip processing of all other components which are not covered by process attribute. Also, components whose rendered attribute evaluates to false during apply request values phase will also be skipped as part of safeguard against tampered requests.

Note that it's in case of ActionSource components (such as <p:commandButton>) very important that you also include the component itself in the process attribute, particularly if you intend to invoke the action associated with the component. So the below example which intends to process only certain input component(s) when a certain command component is invoked ain't gonna work:

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

It would only process the #{bean.foo} and not the #{bean.action}. You'd need to include the command component itself as well:

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

Or, as you apparently found out, using @parent if they happen to be the only components having a common 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>

Or, if they both happen to be the only components of the parent UIForm component, then you can also use @form:

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

This is sometimes undesirable if the form contains more input components which you'd like to skip in processing, more than often in cases when you'd like to update another input component(s) or some UI section based on the current input component in an ajax listener method. You namely don't want that validation errors on other input components are preventing the ajax listener method from being executed.

Then there's the @all. This has no special effect in process attribute, but only in update attribute. A process="@all" behaves exactly the same as process="@form". HTML doesn't support submitting multiple forms at once anyway.

There's by the way also a @none which may be useful in case you absolutely don't need to process anything, but only want to update some specific parts via update, particularly those sections whose content doesn't depend on submitted values or action listeners.

Noted should be that the process attribute has no influence on the HTTP request payload (the amount of request parameters). Meaning, the default HTML behavior of sending "everything" contained within the HTML representation of the <h:form> will be not be affected. In case you have a large form, and want to reduce the HTTP request payload to only these absolutely necessary in processing, i.e. only these covered by process attribute, then you can set the partialSubmit attribute in PrimeFaces Ajax components as in <p:commandXxx ... partialSubmit="true"> or <p:ajax ... partialSubmit="true">. Alternatively, you can also use <o:form> of OmniFaces 3.0+ which defaults to this behavior.

The standard JSF equivalent to the PrimeFaces specific process is execute from <f:ajax execute>. It behaves exactly the same except that it doesn't support a comma-separated string while the PrimeFaces one does (although I personally recommend to just stick to space-separated convention), nor the @parent keyword. Also, it may be useful to know that <p:commandXxx process> defaults to @form while <p:ajax process> and <f:ajax execute> defaults to @this. Finally, it's also useful to know that process supports the so-called "PrimeFaces Selectors", see also How do PrimeFaces Selectors as in update="@(.myClass)" work?


<p:commandXxx update> <p:ajax update> <f:ajax render>

The update attribute is client side and can affect the HTML representation of all UIComponents. The update attribute tells JavaScript (the one responsible for handling the ajax request/response), using a space-separated list of client IDs, which parts in the HTML DOM tree need to be updated as response to the form submit.

JSF will then prepare the right ajax response for that, containing only the requested parts to update. JSF will skip all other components which are not covered by update attribute in the ajax response, hereby keeping the response payload small. Also, components whose rendered attribute evaluates to false during render response phase will be skipped. Note that even though it would return true, JavaScript cannot update it in the HTML DOM tree if it was initially false. You'd need to wrap it or update its parent instead. See also Ajax update/render does not work on a component which has rendered attribute.

Usually, you'd like to update only the components which really need to be "refreshed" in the client side upon (partial) form submit. The example below updates the entire parent form via @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>

(note that process attribute is omitted as that defaults to @form already)

Whilst that may work fine, the update of input and command components is in this particular example unnecessary. Unless you change the model values foo and bar inside action method (which would in turn be unintuitive in UX perspective), there's no point of updating them. The message components are the only which really need to be updated:

<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>

However, that gets tedious when you have many of them. That's one of the reasons why PrimeFaces Selectors exist. Those message components have in the generated HTML output a common style class of ui-message, so the following should also do:

<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>

(note that you should keep the IDs on message components, otherwise @(...) won't work! Again, see How do PrimeFaces Selectors as in update="@(.myClass)" work? for detail)

The @parent updates only the parent component, which thus covers the current component and all siblings and their children. This is more useful if you have separated the form in sane groups with each its own responsibility. The @this updates, obviously, only the current component. Normally, this is only necessary when you need to change one of the component's own HTML attributes in the action method. E.g.

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

Imagine that the oncomplete needs to work with the value which is changed in action, then this construct wouldn't have worked if the component isn't updated, for the simple reason that oncomplete is part of generated HTML output (and thus all EL expressions in there are evaluated during render response).

The @all updates the entire document, which should be used with care. Normally, you'd like to use a true GET request for this instead by either a plain link (<a> or <h:link>) or a redirect-after-POST by ?faces-redirect=true or ExternalContext#redirect(). In effects, process="@form" update="@all" has exactly the same effect as a non-ajax (non-partial) submit. In my entire JSF career, the only sensible use case I encountered for @all is to display an error page in its entirety in case an exception occurs during an ajax request. See also What is the correct way to deal with JSF 2.0 exceptions for AJAXified components?

The standard JSF equivalent to the PrimeFaces specific update is render from <f:ajax render>. It behaves exactly the same except that it doesn't support a comma-separated string while the PrimeFaces one does (although I personally recommend to just stick to space-separated convention), nor the @parent keyword. Both update and render defaults to @none (which is, "nothing").


See also:

这篇关于了解PrimeFaces流程/更新和JSF f:ajax执行/渲染属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆