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 ...)?
And how the client ID will be generated (if providing /not providing component ID and not, randomly or using a specific logic...) ?
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 ...)?
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.
And how the client ID will be generated (if providing /not providing component ID and not, randomly or using a specific logic...)?
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:
public abstract String getClientId(FacesContext context)
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.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 aNamingContainer
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:Find the closest ancestor to this component in the view hierarchy that implements
NamingContainer
. CallgetContainerClientId()
on it and save the result as theparentId
local variable. CallgetId()
on this component and save the result as themyId
local variable. IfmyId
isnull
, callcontext.getViewRoot().createUniqueId()
and assign the result tomyId
. IfparentId
is non-null
, letmyId
equalparentId +
UINamingContainer.getSeparatorChar(javax.faces.context.FacesContext)
+ myId
. CallRenderer.convertClientId(javax.faces.context.FacesContext, java.lang.String)
, passingmyId
, and return the result.
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.
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:
public String createUniqueId()
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 thisUIViewRoot
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With