PrimeFaces 中可能的命名容器有哪些?当我们想使用 更新表单上的某些 UI 控件时,为什么需要为 Ajax 更新调用附加命名容器 ID update=":mainForm:MainAccordian:userNameTextbox"
?
3 回答
Prime 面孔中可能的命名容器是什么
在 JSF 中,命名容器派生自UINamingContainer。
当我们想使用 update=":mainForm:MainAccordian:userNameTextbox" 更新表单上的某些 UI 控件时,为什么需要为 Ajax 更新调用附加命名容器 ID
可以说,如果您在页面中<h:outputText value="test1" id="userNameTextbox" />
添加另一个<h:outputText value="test2" id="userNameTextbox" />
,您将收到一个错误,指出您有一个重复的 ID。您可以在 JavaDoc 中查找UIComponent.setId(String):
设置此 UIComponent 的组件标识符(如果有)。组件标识符必须遵守以下语法限制: 不能是长度为零的字符串。第一个字符必须是字母或下划线 (' ')。后续字符必须是字母、数字、下划线 (' ') 或破折号 ('-')。
..此外,对您很重要:
指定的标识符必须在作为最近的祖先 UIComponent 的后代的所有组件(包括构面)中是唯一的,或者在整个组件树的范围内(如果没有这样的祖先是 NamingContainer)。
Means that you cannot have two components with the same ID under the same NamingContainer (if you have no NamingContainer at all, the entire tree is counted as NamingContainer).
Therefore you need to add a NamingContainer, like a <h:form id="myNamingContainer" />
Lets take following example:
<h:outputText value="test1" id="userNameTextbox" />
<h:form id="container1">
<h:outputText value="test2" id="userNameTextbox" />
</h:form>
<h:form id="container2">
<h:outputText value="test3" id="userNameTextbox" />
</h:form>
.. and you want to do an update to userNameTextbox. Which userNameTextbox are you refering to because there are 3?
The first one? Then update userNameTextbox
The second one? Then update container1:userNameTextbox
The third one? Then update container2:userNameTextbox
After having IntelliJ scan all my JARs for implementations of javax.faces.component.NamingContainer
here is what I found:
From PrimeFaces 5.3
- AccordionPanel
- Carousel
- Columns
- DataGrid
- DataList
- DataScroller
- DataTable
- Page
- Ring
- SubTable
- Subview
- TabView
- TreeTable
- UIData
- UITabPanel
From MyFaces 2.1
- HtmlDataTable
- HtmlForm
- UITree
- UIForm
Naming Containers in Prime Faces
As we can see in JSF Reference
NamingContainer is an interface that must be implemented by any UIComponent that wants to be a naming container. Naming containers affect the behavior of the UIComponent.findComponent(java.lang.String) and UIComponent.getClientId() methods;
So to find Naming Containers in PF you need to check hierarchy of NamingContainer
interface. In Eclipse you can do this for example by Ctrl+T shortcut on NamingContainer
.
In PF 5.3 there are for example: AccordionPanel
, Carousel
, Columns
, DataGrid
, DataList
, DataScroller
, DataTable
, Ring
, SubTable
, TabView
, Tree
, TreeTable
.
Naming Container influence on component id
- Default behavior
Naming Container provide a naming scope for its child components. So it always add prefix to his children id. So id of child component is: parent_component_id".concat(":").concat("component_id")
.
There is one pro tip that I had read in JavaServer Faces 2.0, The Complete Reference that even if you not add NamingContainer to your page it is always automatically added by JSF itself :) There also exist special algorith of this creation (Chapter 11: Building Custom UI Component -> Box called "Rules for Creating the Top-Level Component for a Composite Component"). Of course when you don't set id, it will be generate automatically (for example j_idt234). So full component id may look like this: "j_idt123:j_idt234:j_idt345".
- Change component name separator (since JSF 2.x)
There is a way to override default component name separator (":"). You can define it in web.xml as context-param with name javax.faces.SEPARATOR_CHAR
. For example:
<context-param>
<param-name>javax.faces.SEPARATOR_CHAR</param-name>
<param-value>-</param-value>
</context-param>
- UIForm attribute "prependId"
To avoid adding scope to child component there is an attribute (only in UIForm component). But this is not recommended solution. Take a look for example at uiform-with-prependid-false-breaks-fajax-render
Component id usage (for example in "update", "process")
- Whole id
You can use whole id: "componentParent:component". This is not recommended (code will be fragile; any id changes will cause need to change ids in many places).
- Relative ids in same level of naming container
Inside one naming container you can use simple component id.
- PrimeFaces Search Expression Framework
If you don't know this feature please take a look in PrimeFaces documentation. Prime Faces provide Search Expression Framework with couple of very usefull mechanism.
You can search by keywords.
Keywords are the easier way to reference components, they resolve to ids so that if an id changes, the reference does not need to change. Core JSF provides a couple of keywords and PrimeFaces provides more along with composite expression support.
Examples: @this
(current component), @form
(closest ancestor form), @namingcontainer
(closest ancestor naming container), @parent
, @widgetVar(name)
.
You can also mixed those keywords in quite complex paths (Composite Expressions) for example: @form:@parent
, @this:@parent:@parent
The second posibility PF gives you are PrimeFaces Selectors (PFS).
PFS integrates jQuery Selector API with JSF component referencing model so that referencing can be done using jQuery Selector API instead of core id based JSF model.
So you can for example:
- update all form elements by
update="@(form)"
- update all datatables by
update="@(.ui-datatable)"
- update all components that has styleClass named "myStyle" by
update="@(.myStyle)"
Quite a powerful tool.