问题描述
为了进一步了解JSF(2.x)中的clientID生成,有人可以向我解释一下JSF何时确切地生成客户端ID(哪个生命周期阶段,构建时间或呈现时间...)?
In order to more understand the clientID generation in JSF (2.x), could someone explain to me when exactely does JSF generates the client ID (which lifecycle phase, build time or render time ...)?
以及如何生成客户端ID(如果提供/不提供组件ID,是否随机提供或使用特定逻辑...)?
And how the client ID will be generated (if providing /not providing component ID and not, randomly or using a specific logic...) ?
推荐答案
它必须以HTML响应结尾.因此,它是在渲染响应期间生成的.如果在 UIComponent#getClientId()
方法,那么您会在堆栈的更下方看到(如果是Mojarra)已调用RenderResponsePhase#execute()
.这足以说明命中断点时生命周期中的当前阶段.
It has to end up in HTML response. It's thus generated during render response. If you put a debug breakpoint on UIComponent#getClientId()
method, then you'll see further down in the stack that (in case of Mojarra) RenderResponsePhase#execute()
has been invoked. This is sufficient hint about the current phase in the lifecycle when the breakpoint is hit.
抽象UIComponent#getClientId()
方法的具体实现可以在 UIComponentBase#getClientId()
. 其源代码可在grepcode上找到.它的生成方式仅在其javadoc :
The concrete implementation of the abstract UIComponent#getClientId()
method can be found in UIComponentBase#getClientId()
. Its source code can be found at grepcode. How it will be generated is just described in its javadoc:
返回此组件的客户端标识符,并在必要时生成一个.关联的 Renderer
(如果有) ,系统会要求将clientId转换为适合传输给客户端的格式.
Return a client-side identifier for this component, generating one if necessary. The associated Renderer
, if any, will be asked to convert the clientId to a form suitable for transmission to the client.
在实例的整个生命周期中,从此方法返回的值必须是相同的值,除非更改了组件的id
属性或将该组件放置在 NamingContainer
,其客户端ID发生了变化(例如, UIData
).但是,即使在这些情况下,对该方法的连续调用也必须始终返回相同的值.在确定clientId时,实现必须遵循以下步骤:
The return from this method must be the same value throughout the lifetime of the instance, unless the id
property of the component is changed, or the component is placed in a NamingContainer
whose client ID changes (for example, UIData
). However, even in these cases, consecutive calls to this method must always return the same value. The implementation must follow these steps in determining the clientId:
在实现NamingContainer
的视图层次结构中找到最接近此组件的祖先.在其上调用getContainerClientId()
并将结果保存为parentId
局部变量.调用 getId()
在此组件上,并将结果另存为myId
局部变量.如果myId
是null
,则调用 context.getViewRoot().createUniqueId()
并将结果分配给myId
.如果parentId
不是-null
,则使myId
等于parentId +
UINamingContainer.getSeparatorChar(javax.faces.context.FacesContext)
+ myId
.调用 Renderer.convertClientId(javax.faces.context.FacesContext, java.lang.String)
,传递myId
,然后返回结果.
Find the closest ancestor to this component in the view hierarchy that implements NamingContainer
. Call getContainerClientId()
on it and save the result as the parentId
local variable. Call getId()
on this component and save the result as the myId
local variable. If myId
is null
, call context.getViewRoot().createUniqueId()
and assign the result to myId
. If parentId
is non-null
, let myId
equal parentId +
UINamingContainer.getSeparatorChar(javax.faces.context.FacesContext)
+ myId
. Call Renderer.convertClientId(javax.faces.context.FacesContext, java.lang.String)
, passing myId
, and return the result.
很清楚,是吗?最重要的部分可能是记住实现NamingContainer
并因此在其客户端ID前面加上前缀的组件.在标准JSF 2.x中,至少为<h:form>
,<h:dataTable>
,<ui:repeat>
,<f:subview>
和<cc:implementation>
. 如果您轻轻地给所有组件一个固定的ID ,那么您还将在此模式中看到生成的HTML输出.
Pretty clear, is it? The most important part is perhaps memorizing components which implement NamingContainer
and thus prepend their client ID. In standard JSF 2.x, that are at least <h:form>
, <h:dataTable>
, <ui:repeat>
, <f:subview>
and <cc:implementation>
. If you gently give all components a fixed ID, then you'll also see that pattern back in the generated HTML output.
如果不为这些组件提供固定的ID,则将使用JSF生成的ID,该ID可通过 UIViewRoot#createUniqueId()
(上面的javadoc摘录中已经暗示). 其Javadoc 说:
If you don't give those components a fixed ID, then instead the JSF-generated ID will be used which can be obtained via UIViewRoot#createUniqueId()
(as already hinted in the above javadoc extract). Its javadoc says:
生成组件的标识符.标识符将带有 UNIQUE_ID_PREFIX
,并且在此UIViewRoot
的非NamingContainer子树中是唯一的.
Generate an identifier for a component. The identifier will be prefixed with UNIQUE_ID_PREFIX
, and will be unique within the non-NamingContainer child sub-trees of this UIViewRoot
.
该前缀为 j_id
.尚不清楚实现应该如何生成,因此所有实现者都可以自由地实现它.他们通常使用树中组件数量的递增索引.因此,第一个组件UIViewRoot
的ID为j_id1
.它的第一个孩子可以得到j_id2
的ID. Etcetera.您可以通过在UIViewRoot#createUniqueId()
方法或什至 UIComponentBase#setId()
方法.
That prefix is j_id
. It isn't explicit on how the implementation should generate it, so all implementors are free to implement it. They usually use an incremented index of the component count in the tree. So, the first component, the UIViewRoot
, could get an ID of j_id1
. Its first child could get an ID of j_id2
. Etcetera. You can track back the logic by putting a debug breakpoint on UIViewRoot#createUniqueId()
method or even the UIComponentBase#setId()
method.
- 如何找出ajax更新/渲染的组件?找不到表达式为"foo"的组件;引用自"bar"
- 默认情况下,JSF会生成无法使用的ID,这些ID与网络标准的CSS部分不兼容
- 在重复使用时避免重复的ID同一命名容器中的facelets组成
- How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
- By default, JSF generates unusable ids, which are incompatible with css part of web standards
- Avoiding duplicate ids when reusing facelets compositions in the same naming container
这篇关于在JSF中何时以及如何生成clientID?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!