<p:commandXxx process>
<p:ajax process>
<f:ajax execute>
process
属性作用于服务端,其属性值只会影响实现了EditableValueHolder
(input这类标签)或ActionSource
(command这类标签)接口的UIComponent
。通过使用空格分隔的client ID列表,process属性告诉JSF,在表单提交时,具体是哪个组件必须在JSF的生命周期中被处理。
JSF将会应用请求值(通过组件自己的client ID查找HTTP请求的参数,如果组件是实现了EditableValueHolder
接口的话,将会其设置其为提交的值,如果是实现了ActionSource
接口的话,则会将一个新的ActionEvent
加入事件队列),转换、验证和更新模型的值(只针对实现了EditableValueHolder
接口的组件),最后触发队列中的ActionEvent
(只针对实现了ActionSource
接口的组件)。JSF会跳过处理所有其它没有被process
属性包含的组件。并且,作为一种对付请求篡改的防护措施,rendered
属性为false
的组件在应用请求值阶段也会被跳过。
注意了,对于ActionSource
组件(比如<p:commandButton>
),将组件自身包含进process
属性,这非常重要的,特别是当你想要触发和此组件相关的行为时。因此,下面的例子,想要在command组件触发时只处理input组件,这将不会成功。
<p:inputText id="foo" value="#{bean.foo}" />
<p:commandButton process="foo" action="#{bean.action}" />
只会执行#{bean.fool},而不会执行#{bean.action},你需要把command组件自己也包含进process中:
<p:inputText id="foo" value="#{bean.foo}" />
<p:commandButton process="@this foo" action="#{bean.action}" />
或者,正如你之前发现的,如果这两个组件拥有唯一的父组件,可以使用@parent:
<p:panel><!-- 是什么组件无关紧要,只要是个公共的父组件. -->
<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>
有时表单包含的input组件过多,你想要跳过对它们的处理,那@form就不太适合了。经常出现的情况就是,你想要在一个ajax监听器方法中更新另一个input组件或者基于input组件上的UI部件。即此时你不希望其它input组件因为验证错误影响到ajax监听器方法的执行。
那么就用@all
。它并不作用于process
属性上,而只作用于update
属性。process="@all
“的效果和process="@form"
一样。HTML不支持一次提交多个表单。
顺便一提,假如你完全不需要处理任何东西,只想通过update
属性更新一些特定的区域,尤其是那些内容不依赖于提交的值或者action监听器的区域,那么@none
可能就有用了。
在标准JSF中,与PrimeFaces中process
等同的属性为<f:ajax excute>
的excute
属性。它们效果完全相同,但是execute
不支持以逗号分隔的字符串,而PrimeFaces的process
支持(仅管我个人推荐遵守空格分隔的惯例),execute也无法使用@parent
关键字。并且,<p:commandXxx process> 缺省情况下为@form
,<p:ajax process>
和<f:ajax execute>
缺省为@this。最后,process
还支持所谓的PrimeFaces选择器,see also How do PrimeFaces Selectors as in update=”@(.myClass)” work?
<p:commandXxx update>
<p:ajax update>
<f:ajax render>
update
属性作用于客户端,其属性值会影响HTML显示的所有UIComponents
。通过使用空格分隔的client ID列表,update
属性告诉JavaScript(负责处理ajax的请求/响应)HTML DOM树的哪些部分需要被更新以响应表单的提交。
然后JSF将为其准备正确的ajax响应,其中仅仅包含被要求更新的部分。 JSF会跳过处理所有其它在ajax响应中没有被update
属性包含的组件,通过这种方式,来将响应的负荷保持在一个较低的水平。在渲染响应阶段中rendered
属性为false
的组件在应用请求值阶段也会被跳过。 注意,就算rendered
将来会为true
,但如果最初是false
的话,JavaScript也不会在HTML DOM树中更新此组件。 你需要将其包装一下或者更新其父组件。See also Ajax update/render does not work on a component which has rendered attribute.
通常情况下,你只想在客户端表单提交时更新那些真正需要被“刷新”的组件。下面的例子通过使用@form
更新了整个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
)
仅管这可以良好的运行,但是input和command组件的更新在此例中却是没有必要的。除非你想要在action
方法中改变模型的值foo
和bar
,否则更新毫无意义。只有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="foo_m bar_m" />
</h:form>
但是,如果要更新的组件很多的话,这么写会变得很冗长。于是PrimeFaces选择器应运而生。这些message组件在生成的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>
(注意你应该保留message组件的ID,否则@(…)不会产生作用!Again, see How do PrimeFaces Selectors as in update=”@(.myClass)” work? for detail)
@parent
只更新其父组件,如此一来就包含了当前组件、同级组件和其下的子组件。按照@…的职责将其明确分类会更加合理。 @this
,不必多说,只更新当前的组件。正常情况下,只有当你需要在action方法中改变一个组件自身的HTML属性时,@this
才会发挥效用。 E.g.
<p:commandButton action="#{bean.action}" update="@this"
oncomplete="doSomething('#{bean.value}')" />
想象一下,oncomplete
属性需要配合value
属性,而value
又会在action
中被改变,如果当前所在组件不被更新的话,oncomplete
就不会执行,原因很简单,oncomplete
属性是生成的HTML的一部分(如此一来,其中所有的EL表达式都是在渲染响应阶段求值的)
@all
更新整个文件,使用需谨慎。正常情况下,你会使用一个普通的链接( <a>
或者<h:link>
),或者通过?faces-redirect=true
或 ExternalContext#redirect()
进行重定向,来发送一个真实的GET请求。实际上,作为一个非ajax的提交,process="@form"
update="@all"
效果完全相同。在我使用JSF的整个职业生涯中,我唯一一次遇到@all
的合理使用案例是显示一张错误页面,防止ajax请求中出现异常。See also What is the correct way to deal with JSF 2.0 exceptions for AJAXified components?
在标准JSF中,与PrimeFaces中update
等同的属性为<f:ajax render>
的render
属性。它们效果完全相同,但是render
不支持以逗号分隔的字符串,而PrimeFaces的update
支持(仅管我个人推荐遵守空格分隔的惯例),render
也无法使用@parent
关键字。update和render属性都缺省为@none
See also:
- How to find out client ID of component for ajax update/render? Cannot find component with expression “foo” referenced from “bar”
- Execution order of events when pressing PrimeFaces p:commandButton
- How to decrease request payload of p:ajax during e.g. p:dataTable pagination
- How to show details of current row from p:dataTable in a p:dialog and update after save
- How to use <h:form> in JSF page? Single form? Multiple forms? Nested forms?