The following code is inspired from PrimeFaces DataGrid + DataTable Tutorials and put into a <p:tab>
of a <p:tabView>
residing in a <p:layoutUnit>
of a <p:layout>
. Here is the inner part of the code (starting from p:tab
component); the outer part is trivial.
<p:tabView id="tabs">
<p:tab id="search" title="Search">
<h:form id="insTable">
<p:dataTable id="table" var="lndInstrument" value="#{instrumentBean.instruments}">
<p:column>
<p:commandLink id="select" update="insTable:display" oncomplete="dlg.show()">
<f:setPropertyActionListener value="#{lndInstrument}"
target="#{instrumentBean.selectedInstrument}" />
<h:outputText value="#{lndInstrument.name}" />
</p:commandLink>
</p:column>
</p:dataTable>
<p:dialog id="dlg" modal="true" widgetVar="dlg">
<h:panelGrid id="display">
<h:outputText value="Name:" />
<h:outputText value="#{instrumentBean.selectedInstrument.name}" />
</h:panelGrid>
</p:dialog>
</h:form>
</p:tab>
</p:tabView>
When I click the <p:commandLink>
, the code stops working and gives the message:
Cannot find component with expression "insTable:display" referenced from "tabs:insTable:select".
When I try the same using <f:ajax>
, it fails with a different message basically telling the same:
<f:ajax>
contains an unknown id "insTable:display" cannot locate it in the context of the component "tabs:insTable:select"
How is this caused and how can I solve it?
It's because the tab is a naming container aswell... your update should be
update="Search:insTable:display"
What you can do aswell is just place your dialog outside the form and still inside the tab then it would be:update="Search:display"
Try change
update="insTable:display"
toupdate="display"
. I believe you cannot prefix the id with the form ID like that.first of all: as far as i know placing dialog inside a tabview is a bad practice... you better take it out...
and now to your question:
sorry, took me some time to get what exactly you wanted to implement,
did at my web app myself just now, and it works
as I sayed before place the p:dialog out side the `p:tabView ,
leave the p:dialog as you initially suggested :
and the p:commandlink should look like this (all i did is to change the update attribute)
the same works in my web app, and if it does not work for you , then i guess there is something wrong in your java bean code...
Look in HTML output for actual client ID
You need to look in the generated HTML output to find out the right client ID. Open the page in browser, do a rightclick and View Source. Locate the HTML representation of the JSF component of interest and take its
id
as client ID. You can use it in an absolute or relative way depending on the current naming container. See following chapter.Note: if it happens to contain iteration index like
:0:
,:1:
, etc (because it's inside an iterating component), then you need to realize that updating a specific iteration round is not always supported. See bottom of answer for more detail on that.Memorize
NamingContainer
components and always give them a fixed IDIf a component which you'd like to reference by ajax process/execute/update/render is inside the same
NamingContainer
parent, then just reference its own ID.If it's not inside the same
NamingContainer
, then you need to reference it using an absolute client ID. An absolute client ID starts with theNamingContainer
separator character, which is by default:
.NamingContainer
components are for example<h:form>
,<h:dataTable>
,<p:tabView>
,<cc:implementation>
(thus, all composite components), etc. You recognize them easily by looking at the generated HTML output, their ID will be prepended to the generated client ID of all child components. Note that when they don't have a fixed ID, then JSF will use an autogenerated ID inj_idXXX
format. You should absolutely avoid that by giving them a fixed ID. The OmniFacesNoAutoGeneratedIdViewHandler
may be helpful in this during development.If you know to find the javadoc of the
UIComponent
in question, then you can also just check in there whether it implements theNamingContainer
interface or not. For example, theHtmlForm
(theUIComponent
behind<h:form>
tag) shows it implementsNamingContainer
, but theHtmlPanelGroup
(theUIComponent
behind<h:panelGroup>
tag) does not show it, so it does not implementNamingContainer
. Here is the javadoc of all standard components and here is the javadoc of PrimeFaces.Solving your problem
So in your case of:
The generated HTML output of
<h:panelGrid id="display">
looks like this:You need to take exactly that
id
as client ID and then prefix with:
for usage inupdate
:Referencing outside include/tagfile/composite
If this command link is inside an include/tagfile, and the target is outside it, and thus you don't necessarily know the ID of the naming container parent of the current naming container, then you can dynamically reference it via
UIComponent#getNamingContainer()
like so:Or, if this command link is inside a composite component and the target is outside it:
Or, if both the command link and target are inside same composite component:
See also Get id of parent naming container in template for in render / update attribute
How does it work under the covers
This all is specified as "search expression" in the
UIComponent#findComponent()
javadoc:Note that PrimeFaces also adheres the JSF spec, but RichFaces uses "some additional exceptions".
Those additional exceptions are nowhere in detail described, but it's known that relative component IDs (i.e. those not starting with
:
) are not only searched in the context of the closest parentNamingContainer
, but also in all otherNamingContainer
components in the same view (which is a relatively expensive job by the way).Never use
prependId="false"
If this all still doesn't work, then verify if you aren't using
<h:form prependId="false">
. This will fail during processing the ajax submit and render. See also this related question: UIForm with prependId="false" breaks <f:ajax render>.Referencing specific iteration round of iterating components
It was for long time not possible to reference a specific iterated item in iterating components like
<ui:repeat>
and<h:dataTable>
like so:However, since Mojarra 2.2.5 the
<f:ajax>
started to support it (it simply stopped validating it; thus you would never face the in the question mentioned exception anymore; another enhancement fix is planned for that later).This only doesn't work yet in current MyFaces 2.2.7 and PrimeFaces 5.2 versions. The support might come in the future versions. In the meanwhile, your best bet is to update the iterating component itself, or a parent in case it doesn't render HTML, like
<ui:repeat>
.When using PrimeFaces, consider Search Expressions or Selectors
PrimeFaces Search Expressions allows you to reference components via JSF component tree search expressions. JSF has several builtin:
@this
: current component@form
: parentUIForm
@all
: entire document@none
: nothingPrimeFaces has enhanced this with new keywords and composite expression support:
@parent
: parent component@namingcontainer
: parentUINamingContainer
@widgetVar(name)
: component as identified by givenwidgetVar
You can also mix those keywords in composite expressions such as
@form:@parent
,@this:@parent:@parent
, etc.PrimeFaces Selectors (PFS) as in
@(.someclass)
allows you to reference components via jQuery CSS selector syntax. E.g. referencing components having all a common style class in the HTML output. This is particularly helpful in case you need to reference "a lot of" components. This only prerequires that the target components have all a client ID in the HTML output (fixed or autogenerated, doesn't matter). See also How do PrimeFaces Selectors as in update="@(.myClass)" work?